1. بررسی اجمالی
Google Cloud Spanner یک سرویس پایگاه داده رابطهای با مقیاسپذیر افقی، توزیعشده در سطح جهانی و کاملاً مدیریت شده است که تراکنشهای ACID و معنایی SQL را بدون کاهش عملکرد و در دسترس بودن بالا ارائه میکند.
در این آزمایشگاه، نحوه راه اندازی یک نمونه Cloud Spanner را خواهید آموخت. شما مراحل ایجاد یک پایگاه داده و طرحواره ای را طی خواهید کرد که می تواند برای امتیازات بازی استفاده شود. شما با ایجاد یک جدول بازیکنان برای ذخیره اطلاعات بازیکن و یک جدول امتیازات برای ذخیره امتیازات بازیکنان شروع خواهید کرد.
سپس جداول را با داده های نمونه پر می کنید. سپس با اجرای چند پرس و جوی نمونه برتر و در نهایت حذف نمونه برای آزاد کردن منابع، آزمایشگاه را به پایان می رسانید.
چیزی که یاد خواهید گرفت
- نحوه راه اندازی یک نمونه Cloud Spanner.
- نحوه ایجاد پایگاه داده و جداول
- نحوه استفاده از ستون مهر زمان commit
- نحوه بارگیری داده ها در جدول پایگاه داده Cloud Spanner با مُهر زمانی.
- چگونه پایگاه داده Cloud Spanner خود را پرس و جو کنیم.
- چگونه نمونه Cloud Spanner خود را حذف کنیم.
آنچه شما نیاز دارید
چگونه از این آموزش استفاده خواهید کرد؟
تجربه خود را با Google Cloud Platform چگونه ارزیابی می کنید؟
2. راه اندازی و الزامات
تنظیم محیط خود به خود
اگر قبلاً یک حساب Google (Gmail یا Google Apps) ندارید، باید یک حساب ایجاد کنید . به کنسول Google Cloud Platform ( consol.cloud.google.com ) وارد شوید و یک پروژه جدید ایجاد کنید.
اگر قبلاً پروژه ای دارید، روی منوی کشویی انتخاب پروژه در سمت چپ بالای کنسول کلیک کنید:
و روی دکمه "پروژه جدید" در گفتگوی حاصل کلیک کنید تا یک پروژه جدید ایجاد کنید:
اگر قبلاً پروژه ای ندارید، باید یک دیالوگ مانند این را ببینید تا اولین پروژه خود را ایجاد کنید:
گفتگوی بعدی ایجاد پروژه به شما امکان می دهد جزئیات پروژه جدید خود را وارد کنید:
شناسه پروژه را به خاطر بسپارید، که یک نام منحصر به فرد در تمام پروژه های Google Cloud است (نام بالا قبلاً گرفته شده است و برای شما کار نخواهد کرد، متأسفیم!). بعداً در این آزمایشگاه کد به عنوان PROJECT_ID
نامیده خواهد شد.
در مرحله بعد، اگر قبلاً این کار را انجام ندادهاید، برای استفاده از منابع Google Cloud و فعال کردن Cloud Spanner API، باید صورتحساب را در Developers Console فعال کنید .
گذراندن این کد نباید بیش از چند دلار هزینه داشته باشد، اما اگر تصمیم به استفاده از منابع بیشتری داشته باشید یا آنها را در حال اجرا رها کنید، ممکن است بیشتر باشد (به بخش "پاکسازی" در انتهای این سند مراجعه کنید). قیمت Google Cloud Spanner در اینجا مستند شده است.
کاربران جدید Google Cloud Platform واجد شرایط استفاده آزمایشی رایگان 300 دلاری هستند که باید این نرم افزار کد را کاملاً رایگان کند.
Google Cloud Shell Setup
در حالی که Google Cloud و Spanner را میتوان از راه دور از لپتاپ شما کار کرد، در این نرمافزار از Google Cloud Shell استفاده میکنیم، یک محیط خط فرمان که در Cloud اجرا میشود.
این ماشین مجازی مبتنی بر دبیان با تمام ابزارهای توسعه که شما نیاز دارید بارگذاری شده است. این دایرکتوری اصلی 5 گیگابایتی دائمی را ارائه می دهد و در Google Cloud اجرا می شود و عملکرد شبکه و احراز هویت را بسیار افزایش می دهد. این بدان معنی است که تمام چیزی که برای این کد لبه نیاز دارید یک مرورگر است (بله، روی کروم بوک کار می کند).
- برای فعال کردن Cloud Shell از Cloud Console، کافی است روی Activate Cloud Shell کلیک کنید. (تهیه و اتصال به محیط فقط چند لحظه طول می کشد).
پس از اتصال به Cloud Shell، باید ببینید که قبلاً احراز هویت شده اید و پروژه قبلاً روی PROJECT_ID
شما تنظیم شده است.
gcloud auth list
خروجی فرمان
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
خروجی فرمان
[core] project = <PROJECT_ID>
اگر به دلایلی پروژه تنظیم نشد، به سادگی دستور زیر را صادر کنید:
gcloud config set project <PROJECT_ID>
به دنبال PROJECT_ID
خود هستید؟ بررسی کنید از چه شناسه ای در مراحل راه اندازی استفاده کرده اید یا آن را در داشبورد Cloud Console جستجو کنید:
Cloud Shell همچنین برخی از متغیرهای محیطی را به صورت پیشفرض تنظیم میکند که ممکن است هنگام اجرای دستورات آینده مفید باشند.
echo $GOOGLE_CLOUD_PROJECT
خروجی فرمان
<PROJECT_ID>
- در نهایت، منطقه پیش فرض و پیکربندی پروژه را تنظیم کنید.
gcloud config set compute/zone us-central1-f
شما می توانید مناطق مختلفی را انتخاب کنید. برای اطلاعات بیشتر، به مناطق و مناطق مراجعه کنید.
خلاصه
در این مرحله محیط خود را راه اندازی می کنید.
بعدی
در مرحله بعد، یک نمونه Cloud Spanner را تنظیم خواهید کرد.
3. یک نمونه Cloud Spanner راه اندازی کنید
در این مرحله ما نمونه Cloud Spanner خود را برای این Codelab راه اندازی می کنیم. ورودی آچار را جستجو کنید در سمت چپ منوی همبرگر بالا یا با فشار دادن "/" عبارت "Spanner" را جستجو کنید و "Spanner" را تایپ کنید.
بعد، بر روی کلیک کنید و با وارد کردن نام نمونه cloudspanner-leaderboard برای نمونه خود، انتخاب یک پیکربندی (انتخاب یک نمونه منطقه ای) و تنظیم تعداد گره ها، فرم را پر کنید، برای این کد لبه تنها به 1 گره نیاز داریم. برای نمونه های تولید و برای واجد شرایط بودن برای Cloud Spanner SLA، باید 3 یا بیشتر گره را در نمونه Cloud Spanner خود اجرا کنید.
آخرین، اما نه کم اهمیت، روی "ایجاد" کلیک کنید و در عرض چند ثانیه یک نمونه Cloud Spanner در اختیار دارید.
در مرحله بعدی ما از کتابخانه کلاینت جاوا برای ایجاد یک پایگاه داده و طرحواره در نمونه جدید خود استفاده می کنیم.
4. یک پایگاه داده و طرحواره ایجاد کنید
در این مرحله میخواهیم پایگاه داده و طرحواره خود را بسازیم.
بیایید از کتابخانه مشتری جاوا برای ایجاد دو جدول استفاده کنیم. یک جدول بازیکنان برای اطلاعات بازیکن و یک جدول امتیازات برای ذخیره امتیازات بازیکنان. برای انجام این کار، مراحل ایجاد یک برنامه کنسول جاوا در Cloud Shell را طی می کنیم.
ابتدا با تایپ دستور زیر در Cloud Shell، کد نمونه این کد لبه را از Github کلون کنید:
git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git
سپس دایرکتوری را به دایرکتوری "applications" تغییر دهید که در آن برنامه خود را ایجاد خواهید کرد.
cd java-docs-samples/spanner/leaderboard
تمام کدهای مورد نیاز برای این Codelab در دایرکتوری java-docs-samples/spanner/leaderboard/complete
موجود به عنوان یک برنامه C# قابل اجرا با نام Leaderboard
قرار دارد تا در حین پیشروی از طریق Codelab به عنوان مرجع عمل کند. ما یک دایرکتوری جدید ایجاد می کنیم و یک کپی از برنامه Leaderboard در مراحل ایجاد می کنیم.
یک دایرکتوری جدید با نام "codelab" برای برنامه ایجاد کنید و دایرکتوری را با دستور زیر به آن تغییر دهید:
mkdir codelab && cd $_
با استفاده از دستور Maven (mvn) زیر یک برنامه جاوا پایه جدید با نام "Leaderboard" ایجاد کنید:
mvn -B archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=com.google.codelabs -DartifactId=leaderboard -DarchetypeVersion=1.4
این دستور یک برنامه کنسول ساده متشکل از دو فایل اصلی فایل، فایل پیکربندی برنامه Maven pom.xml
و فایل برنامه Java App.java
ایجاد می کند.
سپس، دایرکتوری را به فهرست راهنمای رهبران که به تازگی ایجاد شده است تغییر دهید و محتوای آن را فهرست کنید:
cd leaderboard && ls
باید فایل pom.xml
و فهرست src
را مشاهده کنید:
pom.xml src
اکنون اجازه دهید این برنامه کنسول را با ویرایش App.java
به روز کنیم تا از کتابخانه سرویس گیرنده Java Spanner برای ایجاد یک تابلوی امتیاز متشکل از دو جدول استفاده کنیم. بازیکنان و امتیازات می توانید این کار را درست در ویرایشگر پوسته ابری انجام دهید:
ویرایشگر پوسته ابری را با کلیک بر روی نماد مشخص شده در زیر باز کنید:
pom.xml را در زیر پوشه تابلوی امتیازات باز کنید. فایل pom.xml را که در پوشه java-docs-samples\ spanner\leaderboard\codelab\leaderboard
قرار دارد را باز کنید. این فایل سیستم ساخت maven را برای ساخت برنامه ما در یک jar پیکربندی میکند که شامل همه وابستگیهای ما میشود.
1 بخش مدیریت وابستگی جدید زیر را درست زیر عنصر </properties> موجود اضافه کنید:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-bom</artifactId>
<version>0.83.0-alpha</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
همچنین 1 وابستگی جدید در بخش <وابستگی> موجود اضافه کنید که کتابخانه کلاینت Cloud Spanner Java را به برنامه اضافه می کند.
<dependency>
<!-- Version auto-managed by BOM -->
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner</artifactId>
</dependency>
سپس بخش <build> موجود فایل pom.xml
را با بخش <build> زیر جایگزین کنید:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<finalName>leaderboard</finalName>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.google.codelabs.App</mainClass>
</manifest>
</archive>
<appendAssemblyId>false</appendAssemblyId>
<attach>false</attach>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
</plugins>
</build>
با انتخاب «ذخیره» در منوی «فایل» ویرایشگر Cloud Shell یا با فشار دادن کلیدهای صفحه کلید «Ctrl» و «S» با هم، تغییراتی را که در فایل pom.xml ایجاد کردهاید، ذخیره کنید.
سپس فایل App.java
را در Cloud Shell Editor واقع در پوشه src/main/java/com/google/codelabs/
باز کنید. با قرار دادن کد جاوا زیر در فایل App.java
، کد موجود فایل را با کد مورد نیاز برای ایجاد پایگاه داده leaderboard
و جداول Players
و Scores
جایگزین کنید:
package com.google.codelabs;
import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.spanner.Database;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;
/**
* Example code for using the Cloud Spanner API with the Google Cloud Java client library
* to create a simple leaderboard.
*
* This example demonstrates:
*
* <p>
*
* <ul>
* <li>Creating a Cloud Spanner database.
* </ul>
*/
public class App {
static void create(DatabaseAdminClient dbAdminClient, DatabaseId db) {
OperationFuture<Database, CreateDatabaseMetadata> op =
dbAdminClient.createDatabase(
db.getInstanceId().getInstance(),
db.getDatabase(),
Arrays.asList(
"CREATE TABLE Players(\n"
+ " PlayerId INT64 NOT NULL,\n"
+ " PlayerName STRING(2048) NOT NULL\n"
+ ") PRIMARY KEY(PlayerId)",
"CREATE TABLE Scores(\n"
+ " PlayerId INT64 NOT NULL,\n"
+ " Score INT64 NOT NULL,\n"
+ " Timestamp TIMESTAMP NOT NULL\n"
+ " OPTIONS(allow_commit_timestamp=true)\n"
+ ") PRIMARY KEY(PlayerId, Timestamp),\n"
+ "INTERLEAVE IN PARENT Players ON DELETE NO ACTION"));
try {
// Initiate the request which returns an OperationFuture.
Database dbOperation = op.get();
System.out.println("Created database [" + dbOperation.getId() + "]");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
throw (SpannerException) e.getCause();
} catch (InterruptedException e) {
// Throw when a thread is waiting, sleeping, or otherwise occupied,
// and the thread is interrupted, either before or during the activity.
throw SpannerExceptionFactory.propagateInterrupt(e);
}
}
static void printUsageAndExit() {
System.out.println("Leaderboard 1.0.0");
System.out.println("Usage:");
System.out.println(" java -jar leaderboard.jar "
+ "<command> <instance_id> <database_id> [command_option]");
System.out.println("");
System.out.println("Examples:");
System.out.println(" java -jar leaderboard.jar create my-instance example-db");
System.out.println(" - Create a sample Cloud Spanner database along with "
+ "sample tables in your project.\n");
System.exit(1);
}
public static void main(String[] args) throws Exception {
if (!(args.length == 3 || args.length == 4)) {
printUsageAndExit();
}
SpannerOptions options = SpannerOptions.newBuilder().build();
Spanner spanner = options.getService();
try {
String command = args[0];
DatabaseId db = DatabaseId.of(options.getProjectId(), args[1], args[2]);
DatabaseClient dbClient = spanner.getDatabaseClient(db);
DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
switch (command) {
case "create":
create(dbAdminClient, db);
break;
default:
printUsageAndExit();
}
} finally {
spanner.close();
}
System.out.println("Closed client");
}
}
تغییراتی را که در فایل App.java
ایجاد کردهاید، با انتخاب «ذخیره» در منوی «فایل» Cloud Shell Editor ذخیره کنید.
میتوانید از فایل App.java
در فهرست راهنمای java-docs-samples/spanner/leaderboard/step4/src
استفاده کنید تا نمونهای از نحوه نگاه کردن فایل App.java
خود را پس از افزودن کد برای فعال کردن فرمان create
ببینید.
برای ساختن برنامه خود بسته mvn را از دایرکتوری که pom.xml
شما در آن قرار دارد اجرا کنید:
mvn package
هنگامی که فایل jar جاوا شما با موفقیت ساخته شد، با وارد کردن دستور زیر برنامه به دست آمده را در پوسته ابری اجرا کنید:
java -jar target/leaderboard.jar
شما باید خروجی را مانند زیر ببینید:
Leaderboard 1.0.0 Usage: java -jar leaderboard.jar <command> <instance_id> <database_id> [command_option] Examples: java -jar leaderboard.jar create my-instance example-db - Create a sample Cloud Spanner database along with sample tables in your project.
از این پاسخ می بینیم که این برنامه Leaderboard
است که در حال حاضر یک دستور ممکن دارد: create
. میتوانیم ببینیم که آرگومانهای مورد انتظار دستور create
Instance ID و Database ID هستند.
حالا دستور زیر را اجرا کنید.
java -jar target/leaderboard.jar create cloudspanner-leaderboard leaderboard
پس از چند ثانیه باید پاسخی مانند زیر را مشاهده کنید:
Created database [projects/your-project/instances/cloudspanner-leaderboard/databases/leaderboard]
در بخش Cloud Spanner در Cloud Console، باید پایگاه داده و جداول جدید خود را در منوی سمت چپ مشاهده کنید.
در مرحله بعدی برنامه خود را برای بارگیری برخی از داده ها در پایگاه داده جدید شما به روز می کنیم.
5. بارگذاری داده ها
ما اکنون یک پایگاه داده به نام leaderboard
داریم که شامل دو جدول است. Players
و Scores
اکنون بیایید از کتابخانه مشتری جاوا برای پر کردن جدول Players
با بازیکنان و جدول Scores
خود با امتیازهای تصادفی برای هر بازیکن استفاده کنیم.
اگر قبلاً باز نشده است، ویرایشگر پوسته ابری را با کلیک بر روی نماد برجسته شده در زیر باز کنید:
در مرحله بعد، فایل App.java
را در ویرایشگر پوسته ابری ویرایش کنید تا یک دستور insert
اضافه کنید که می تواند برای وارد کردن 100 بازیکن در جدول Players
استفاده شود یا می توان از آن برای درج 4 امتیاز تصادفی در جدول Scores
برای هر بازیکن در Players
استفاده کرد. جدول
ابتدا بخش imports
را در بالای فایل برنامه بهروزرسانی کنید و آنچه را که در حال حاضر وجود دارد جایگزین کنید تا پس از اتمام کار به شکل زیر باشد:
package com.google.codelabs;
import static com.google.cloud.spanner.TransactionRunner.TransactionCallable;
import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.spanner.Database;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Mutation;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
import com.google.cloud.spanner.TransactionContext;
import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom;
سپس متدهای insert، insertPlayers و insertScores زیر را در زیر متد create()
موجود و بالای متد printUsageAndExit()
موجود اضافه کنید:
static void insert(DatabaseClient dbClient, String insertType) {
try {
insertType = insertType.toLowerCase();
} catch (Exception e) {
// Invalid input received, set insertType to empty string.
insertType = "";
}
if (insertType.equals("players")) {
// Insert players.
insertPlayers(dbClient);
} else if (insertType.equals("scores")) {
// Insert scores.
insertScores(dbClient);
} else {
// Invalid input.
System.out.println("Invalid value for 'type of insert'. "
+ "Specify a valid value: 'players' or 'scores'.");
System.exit(1);
}
}
static void insertPlayers(DatabaseClient dbClient) {
dbClient
.readWriteTransaction()
.run(
new TransactionCallable<Void>() {
@Override
public Void run(TransactionContext transaction) throws Exception {
// Get the number of players.
String sql = "SELECT Count(PlayerId) as PlayerCount FROM Players";
ResultSet resultSet = transaction.executeQuery(Statement.of(sql));
long numberOfPlayers = 0;
if (resultSet.next()) {
numberOfPlayers = resultSet.getLong("PlayerCount");
}
// Insert 100 player records into the Players table.
List<Statement> stmts = new ArrayList<Statement>();
long randomId;
for (int x = 1; x <= 100; x++) {
numberOfPlayers++;
randomId = (long) Math.floor(Math.random() * 9_000_000_000L) + 1_000_000_000L;
Statement statement =
Statement
.newBuilder(
"INSERT INTO Players (PlayerId, PlayerName) "
+ "VALUES (@PlayerId, @PlayerName) ")
.bind("PlayerId")
.to(randomId)
.bind("PlayerName")
.to("Player " + numberOfPlayers)
.build();
stmts.add(statement);
}
transaction.batchUpdate(stmts);
return null;
}
});
System.out.println("Done inserting player records...");
}
static void insertScores(DatabaseClient dbClient) {
boolean playerRecordsFound = false;
ResultSet resultSet =
dbClient
.singleUse()
.executeQuery(Statement.of("SELECT * FROM Players"));
while (resultSet.next()) {
playerRecordsFound = true;
final long playerId = resultSet.getLong("PlayerId");
dbClient
.readWriteTransaction()
.run(
new TransactionCallable<Void>() {
@Override
public Void run(TransactionContext transaction) throws Exception {
// Initialize objects for random Score and random Timestamp.
LocalDate endDate = LocalDate.now();
long end = endDate.toEpochDay();
int startYear = endDate.getYear() - 2;
int startMonth = endDate.getMonthValue();
int startDay = endDate.getDayOfMonth();
LocalDate startDate = LocalDate.of(startYear, startMonth, startDay);
long start = startDate.toEpochDay();
Random r = new Random();
List<Statement> stmts = new ArrayList<Statement>();
// Insert 4 score records into the Scores table
// for each player in the Players table.
for (int x = 1; x <= 4; x++) {
// Generate random score between 1,000,000 and 1,000
long randomScore = r.nextInt(1000000 - 1000) + 1000;
// Get random day within the past two years.
long randomDay = ThreadLocalRandom.current().nextLong(start, end);
LocalDate randomDayDate = LocalDate.ofEpochDay(randomDay);
LocalTime randomTime = LocalTime.of(
r.nextInt(23), r.nextInt(59), r.nextInt(59), r.nextInt(9999));
LocalDateTime randomDate = LocalDateTime.of(randomDayDate, randomTime);
Instant randomInstant = randomDate.toInstant(ZoneOffset.UTC);
Statement statement =
Statement
.newBuilder(
"INSERT INTO Scores (PlayerId, Score, Timestamp) "
+ "VALUES (@PlayerId, @Score, @Timestamp) ")
.bind("PlayerId")
.to(playerId)
.bind("Score")
.to(randomScore)
.bind("Timestamp")
.to(randomInstant.toString())
.build();
stmts.add(statement);
}
transaction.batchUpdate(stmts);
return null;
}
});
}
if (!playerRecordsFound) {
System.out.println("Parameter 'scores' is invalid since "
+ "no player records currently exist. First insert players "
+ "then insert scores.");
System.exit(1);
} else {
System.out.println("Done inserting score records...");
}
}
سپس، برای کاربردی کردن دستور insert
، کد زیر را به متد "main" برنامه خود در switch (command)
اضافه کنید:
case "insert":
String insertType;
try {
insertType = args[3];
} catch (ArrayIndexOutOfBoundsException exception) {
insertType = "";
}
insert(dbClient, insertType);
break;
هنگامی که کارتان تمام شد، دستور switch (command)
باید به شکل زیر باشد:
switch (command) {
case "create":
create(dbAdminClient, db);
break;
case "insert":
String insertType;
try {
insertType = args[3];
} catch (ArrayIndexOutOfBoundsException exception) {
insertType = "";
}
insert(dbClient, insertType);
break;
default:
printUsageAndExit();
}
آخرین مرحله برای تکمیل افزودن قابلیت "insert" به برنامه شما، افزودن متن راهنما برای دستور "insert" به متد printUsageAndExit()
است. خطوط کد زیر را به متد printUsageAndExit()
اضافه کنید تا متن راهنما برای دستور insert اضافه شود:
System.out.println(" java -jar leaderboard.jar insert my-instance example-db players");
System.out.println(" - Insert 100 sample Player records into the database.\n");
System.out.println(" java -jar leaderboard.jar insert my-instance example-db scores");
System.out.println(" - Insert sample score data into Scores sample Cloud Spanner "
+ "database table.\n");
تغییراتی را که در فایل App.java
ایجاد کردهاید، با انتخاب «ذخیره» در منوی «فایل» Cloud Shell Editor ذخیره کنید.
میتوانید از فایل App.java
در فهرست راهنمای java-docs-samples/spanner/leaderboard/step5/src
استفاده کنید تا نمونهای از نحوه نگاه فایل App.java
خود را پس از افزودن کد برای فعال کردن دستور insert
ببینید.
حالا بیایید برنامه را بازسازی و اجرا کنیم تا تأیید کنیم که دستور insert
جدید در لیست دستورات ممکن برنامه گنجانده شده است.
برای ساختن برنامه خود mvn package
از دایرکتوری که pom.xml شما در آن قرار دارد اجرا کنید:
mvn package
هنگامی که فایل jar جاوا شما با موفقیت ساخته شد، دستور زیر را اجرا کنید:
java -jar target/leaderboard.jar
اکنون باید دستور insert
را در خروجی پیش فرض برنامه مشاهده کنید:
Leaderboard 1.0.0 Usage: java -jar leaderboard.jar <command> <instance_id> <database_id> [command_option] Examples: java -jar leaderboard.jar create my-instance example-db - Create a sample Cloud Spanner database along with sample tables in your project. java -jar leaderboard.jar insert my-instance example-db players - Insert 100 sample Player records into the database. java -jar leaderboard.jar insert my-instance example-db scores - Insert sample score data into Scores sample Cloud Spanner database table.
میتوانید از پاسخ ببینید که علاوه بر شناسه نمونه و شناسه پایگاه داده، آرگومان دیگری نیز وجود دارد که میتواند مقدار «بازیکنان» یا «امتیازها» را داشته باشد.
حالا بیایید دستور insert
را با همان مقادیر آرگومان اجرا کنیم که هنگام فراخوانی دستور create
استفاده کردیم و "players" را به عنوان آرگومان اضافی "نوع درج" اضافه کنیم.
java -jar target/leaderboard.jar insert cloudspanner-leaderboard leaderboard players
پس از چند ثانیه باید پاسخی مانند زیر را مشاهده کنید:
Done inserting player records...
اکنون بیایید از کتابخانه مشتری جاوا استفاده کنیم تا جدول Scores
خود را با چهار امتیاز تصادفی همراه با مهرهای زمانی برای هر بازیکن در جدول Players
پر کنیم.
ستون Timestamp
جدول Scores
به عنوان یک ستون "commit timestamp" از طریق عبارت SQL زیر تعریف شد که زمانی که قبلاً دستور create
را اجرا می کردیم اجرا می شد:
CREATE TABLE Scores(
PlayerId INT64 NOT NULL,
Score INT64 NOT NULL,
Timestamp TIMESTAMP NOT NULL OPTIONS(allow_commit_timestamp=true)
) PRIMARY KEY(PlayerId, Timestamp),
INTERLEAVE IN PARENT Players ON DELETE NO ACTION
به ویژگی OPTIONS(allow_commit_timestamp=true)
توجه کنید. این موضوع Timestamp
به یک ستون "Commit timestamp" تبدیل میکند و آن را قادر میسازد تا به طور خودکار با مهر زمانی دقیق تراکنش برای عملیات INSERT و UPDATE در یک ردیف جدول مشخص شود.
همچنین میتوانید مقادیر مُهر زمانی خود را در ستون «مهر زمانی تعهد» درج کنید تا زمانی که یک مهر زمانی با مقداری که در گذشته است وارد کنید، این همان کاری است که ما برای هدف این آزمایشگاه انجام خواهیم داد.
حالا بیایید دستور insert
را با همان مقادیر آرگومان اجرا کنیم که هنگام فراخوانی دستور create
و اضافه کردن "scores" به عنوان آرگومان اضافی "نوع درج" استفاده کردیم.
java -jar target/leaderboard.jar insert cloudspanner-leaderboard leaderboard scores
پس از چند ثانیه باید پاسخی مانند زیر را مشاهده کنید:
Done inserting score records...
insert
در حال اجرا با "نوع درج" مشخص شده به عنوان scores
، روش insertScores
را فراخوانی می کند که از تکه های کد زیر برای درج مهر زمانی تولید شده به طور تصادفی با تاریخ-زمان در گذشته استفاده می کند:
LocalDate endDate = LocalDate.now();
long end = endDate.toEpochDay();
int startYear = endDate.getYear() - 2;
int startMonth = endDate.getMonthValue();
int startDay = endDate.getDayOfMonth();
LocalDate startDate = LocalDate.of(startYear, startMonth, startDay);
long start = startDate.toEpochDay();
...
long randomDay = ThreadLocalRandom.current().nextLong(start, end);
LocalDate randomDayDate = LocalDate.ofEpochDay(randomDay);
LocalTime randomTime = LocalTime.of(
r.nextInt(23), r.nextInt(59), r.nextInt(59), r.nextInt(9999));
LocalDateTime randomDate = LocalDateTime.of(randomDayDate, randomTime);
Instant randomInstant = randomDate.toInstant(ZoneOffset.UTC);
...
.bind("Timestamp")
.to(randomInstant.toString())
برای پر کردن خودکار ستون Timestamp
با مهر زمانی دقیقاً زمانی که تراکنش «Insert» انجام میشود، میتوانید در عوض مقدار ثابت جاوا Value.COMMIT_TIMESTAMP
را مانند قطعه کد زیر وارد کنید:
.bind("Timestamp")
.to(Value.COMMIT_TIMESTAMP)
اکنون که بارگیری داده ها را کامل کردیم، بیایید مقادیری را که به تازگی در جداول جدید خود نوشته ایم بررسی کنیم. ابتدا پایگاه داده leaderboard
را انتخاب کنید و سپس جدول Players
را انتخاب کنید. روی تب Data
کلیک کنید. باید ببینید که دادههایی در ستونهای PlayerId
و PlayerName
جدول دارید.
سپس اجازه دهید با کلیک بر روی جدول Scores
و انتخاب زبانه Data
، بررسی کنیم که جدول امتیازات نیز دارای داده است. باید ببینید که دادههایی در ستونهای PlayerId
، Timestamp
و Score
جدول دارید.
آفرین! بیایید برنامه خود را به روز کنیم تا برخی از پرس و جوها را اجرا کنیم تا بتوانیم از آنها برای ایجاد تابلوی امتیازات بازی استفاده کنیم.
6. کوئری های تابلوی امتیازات را اجرا کنید
اکنون که پایگاه داده خود را راه اندازی کرده ایم و اطلاعات را در جداول خود بارگذاری کرده ایم، بیایید با استفاده از این داده ها یک تابلوی امتیازات ایجاد کنیم. برای این کار باید به چهار سوال زیر پاسخ دهیم:
- کدام بازیکنان "ده" برتر تمام دوران هستند؟
- کدام بازیکنان "ده" برتر سال هستند؟
- کدام بازیکنان "ده" برتر ماه هستند؟
- کدام بازیکنان "ده" برتر هفته هستند؟
بیایید برنامه خود را بهروزرسانی کنیم تا سؤالات SQL را اجرا کنیم که به این سؤالات پاسخ میدهد.
ما یک دستور query
اضافه می کنیم که راهی برای اجرای پرس و جوها برای پاسخ به سوالاتی که اطلاعات مورد نیاز برای تابلوی امتیازات ما را تولید می کند، ارائه می دهد.
فایل App.java
را در Cloud Shell Editor ویرایش کنید تا برنامه بهروزرسانی شود تا دستور query
اضافه شود. دستور query
از دو روش query
تشکیل شده است، یکی که فقط آرگومان DatabaseClient
را می گیرد و دیگری که یک آرگومان timespan
اضافی برای تسهیل فیلتر کردن نتایج با بازه زمانی مشخص شده در ساعت می گیرد.
دو روش query
زیر را در زیر متد insertScores()
موجود و بالای متد printUsageAndExit()
موجود اضافه کنید:
static void query(DatabaseClient dbClient) {
String scoreDate;
String score;
ResultSet resultSet =
dbClient
.singleUse()
.executeQuery(
Statement.of(
"SELECT p.PlayerId, p.PlayerName, s.Score, s.Timestamp "
+ "FROM Players p "
+ "JOIN Scores s ON p.PlayerId = s.PlayerId "
+ "ORDER BY s.Score DESC LIMIT 10"));
while (resultSet.next()) {
scoreDate = String.valueOf(resultSet.getTimestamp("Timestamp"));
score = String.format("%,d", resultSet.getLong("Score"));
System.out.printf(
"PlayerId: %d PlayerName: %s Score: %s Timestamp: %s\n",
resultSet.getLong("PlayerId"), resultSet.getString("PlayerName"), score,
scoreDate.substring(0,10));
}
}
static void query(DatabaseClient dbClient, int timespan) {
String scoreDate;
String score;
Statement statement =
Statement
.newBuilder(
"SELECT p.PlayerId, p.PlayerName, s.Score, s.Timestamp "
+ "FROM Players p "
+ "JOIN Scores s ON p.PlayerId = s.PlayerId "
+ "WHERE s.Timestamp > "
+ "TIMESTAMP_SUB(CURRENT_TIMESTAMP(), "
+ " INTERVAL @Timespan HOUR) "
+ "ORDER BY s.Score DESC LIMIT 10")
.bind("Timespan")
.to(timespan)
.build();
ResultSet resultSet =
dbClient
.singleUse()
.executeQuery(statement);
while (resultSet.next()) {
scoreDate = String.valueOf(resultSet.getTimestamp("Timestamp"));
score = String.format("%,d", resultSet.getLong("Score"));
System.out.printf(
"PlayerId: %d PlayerName: %s Score: %s Timestamp: %s\n",
resultSet.getLong("PlayerId"), resultSet.getString("PlayerName"), score,
scoreDate.substring(0,10));
}
}
سپس، برای اینکه دستور query
کاربردی شود، کد زیر را به switch(command)
در متد "main" برنامه خود اضافه کنید:
case "query":
if (args.length == 4) {
int timespan = 0;
try {
timespan = Integer.parseInt(args[3]);
} catch (NumberFormatException e) {
System.err.println("query command's 'timespan' parameter must be a valid integer.");
System.exit(1);
}
query(dbClient, timespan);
} else {
query(dbClient);
}
break;
آخرین مرحله برای تکمیل افزودن قابلیت "query" به برنامه شما، افزودن متن راهنما برای دستور "query" به متد printUsageAndExit()
است. خطوط کد زیر را به متد printUsageAndExit()
اضافه کنید تا متن راهنما برای دستور query اضافه شود:
System.out.println(" java -jar leaderboard.jar query my-instance example-db");
System.out.println(" - Query players with top ten scores of all time.\n");
System.out.println(" java -jar leaderboard.jar query my-instance example-db 168");
System.out.println(" - Query players with top ten scores within a timespan "
+ "specified in hours.\n");
تغییراتی را که در فایل App.java
ایجاد کردهاید، با انتخاب «ذخیره» در منوی «فایل» Cloud Shell Editor ذخیره کنید.
می توانید از فایل App.java
در دایرکتوری dotnet-docs-samples/applications/leaderboard/step6/src
استفاده کنید تا نمونه ای از نحوه نگاه کردن فایل App.java
خود را پس از افزودن کد برای فعال کردن دستور query
ببینید.
برای ساختن برنامه خود mvn package
از دایرکتوری که pom.xml شما در آن قرار دارد اجرا کنید:
mvn package
حالا اجازه دهید برنامه را اجرا کنیم تا تأیید کنیم که دستور query
جدید در لیست دستورات ممکن برنامه گنجانده شده است. دستور زیر را اجرا کنید:
java -jar target/leaderboard.jar
اکنون باید دستور query
را به عنوان یک گزینه دستور جدید در خروجی پیشفرض برنامه مشاهده کنید:
Leaderboard 1.0.0 Usage: java -jar leaderboard.jar <command> <instance_id> <database_id> [command_option] Examples: java -jar leaderboard.jar create my-instance example-db - Create a sample Cloud Spanner database along with sample tables in your project. java -jar leaderboard.jar insert my-instance example-db players - Insert 100 sample Player records into the database. java -jar leaderboard.jar insert my-instance example-db scores - Insert sample score data into Scores sample Cloud Spanner database table. java -jar leaderboard.jar query my-instance example-db - Query players with top ten scores of all time. java -jar leaderboard.jar query my-instance example-db 168 - Query players with top ten scores within a timespan specified in hours.
از پاسخ میبینید که علاوه بر آرگومانهای Instance ID و Database ID، دستور query
به ما اجازه میدهد تا یک بازه زمانی اختیاری را بر حسب ساعت تعیین کنیم تا از آن برای فیلتر کردن رکوردها بر اساس مقدار آنها در ستون Timestamp
جدول Scores
استفاده کنیم. از آنجایی که آرگومان Timesp در اختیاری است به این معنی است که اگر آرگومان بازه زمانی در آن گنجانده نشود، هیچ رکوردی توسط مهر زمانی فیلتر نخواهد شد. بنابراین میتوانیم از دستور query
بدون مقدار «timespan» برای دریافت لیستی از «ده بازیکن برتر» خود در تمام دوران استفاده کنیم.
بیایید دستور query
را بدون تعیین "timespan" اجرا کنیم، با استفاده از همان مقادیر آرگومان که هنگام اجرای دستور create
استفاده کردیم.
java -jar target/leaderboard.jar query cloudspanner-leaderboard leaderboard
شما باید پاسخی را ببینید که شامل "ده بازیکن برتر" تمام دوران است مانند موارد زیر:
PlayerId: 4018687297 PlayerName: Player 83 Score: 999,618 Timestamp: 2017-07-01
PlayerId: 4018687297 PlayerName: Player 83 Score: 998,956 Timestamp: 2017-09-02
PlayerId: 4285713246 PlayerName: Player 51 Score: 998,648 Timestamp: 2017-12-01
PlayerId: 5267931774 PlayerName: Player 49 Score: 997,733 Timestamp: 2017-11-09
PlayerId: 1981654448 PlayerName: Player 35 Score: 997,480 Timestamp: 2018-12-06
PlayerId: 4953940705 PlayerName: Player 87 Score: 995,184 Timestamp: 2018-09-14
PlayerId: 2456736905 PlayerName: Player 84 Score: 992,881 Timestamp: 2017-04-14
PlayerId: 8234617611 PlayerName: Player 19 Score: 992,399 Timestamp: 2017-12-27
PlayerId: 1788051688 PlayerName: Player 76 Score: 992,265 Timestamp: 2018-11-22
PlayerId: 7127686505 PlayerName: Player 97 Score: 992,038 Timestamp: 2017-12-02
حالا بیایید دستور query
را با آرگومان های لازم برای پرس و جو از "ده بازیکن برتر سال" با تعیین "زمان زمانی" برابر تعداد ساعت های یک سال که 8760 ساعت است، اجرا کنیم.
java -jar target/leaderboard.jar query cloudspanner-leaderboard leaderboard 8760
شما باید پاسخی را ببینید که شامل «ده بازیکن برتر» سال مانند زیر است:
PlayerId: 1981654448 PlayerName: Player 35 Score: 997,480 Timestamp: 2018-12-06
PlayerId: 4953940705 PlayerName: Player 87 Score: 995,184 Timestamp: 2018-09-14
PlayerId: 1788051688 PlayerName: Player 76 Score: 992,265 Timestamp: 2018-11-22
PlayerId: 6862349579 PlayerName: Player 30 Score: 990,877 Timestamp: 2018-09-14
PlayerId: 5529627211 PlayerName: Player 16 Score: 989,142 Timestamp: 2018-03-30
PlayerId: 9743904155 PlayerName: Player 1 Score: 988,765 Timestamp: 2018-05-30
PlayerId: 6809119884 PlayerName: Player 7 Score: 986,673 Timestamp: 2018-05-16
PlayerId: 2132710638 PlayerName: Player 54 Score: 983,108 Timestamp: 2018-09-11
PlayerId: 2320093590 PlayerName: Player 79 Score: 981,373 Timestamp: 2018-05-07
PlayerId: 9554181430 PlayerName: Player 80 Score: 981,087 Timestamp: 2018-06-21
حالا بیایید دستور query
را برای پرس و جو از "ده بازیکن برتر" ماه با تعیین یک "زمان زمانی" برابر با تعداد ساعت های یک ماه که 730 ساعت است، اجرا کنیم.
java -jar target/leaderboard.jar query cloudspanner-leaderboard leaderboard 730
شما باید پاسخی را ببینید که شامل "ده بازیکن برتر" ماه است مانند زیر:
PlayerId: 3869829195 PlayerName: Player 69 Score: 949,686 Timestamp: 2019-02-19
PlayerId: 7448359883 PlayerName: Player 20 Score: 938,998 Timestamp: 2019-02-07
PlayerId: 1981654448 PlayerName: Player 35 Score: 929,003 Timestamp: 2019-02-22
PlayerId: 9336678658 PlayerName: Player 44 Score: 914,106 Timestamp: 2019-01-27
PlayerId: 6968576389 PlayerName: Player 40 Score: 898,041 Timestamp: 2019-02-21
PlayerId: 5529627211 PlayerName: Player 16 Score: 896,433 Timestamp: 2019-01-29
PlayerId: 9395039625 PlayerName: Player 59 Score: 879,495 Timestamp: 2019-02-09
PlayerId: 2094604854 PlayerName: Player 39 Score: 860,434 Timestamp: 2019-02-01
PlayerId: 9395039625 PlayerName: Player 59 Score: 849,955 Timestamp: 2019-02-21
PlayerId: 4285713246 PlayerName: Player 51 Score: 805,654 Timestamp: 2019-02-02
حالا بیایید دستور query
را برای پرس و جو از "ده بازیکن برتر" هفته با تعیین یک "زمان زمانی" برابر تعداد ساعت در هفته که 168 ساعت است، اجرا کنیم.
java -jar target/leaderboard.jar query cloudspanner-leaderboard leaderboard 168
شما باید پاسخی را ببینید که شامل "ده بازیکن برتر" هفته مانند زیر است:
PlayerId: 3869829195 PlayerName: Player 69 Score: 949,686 Timestamp: 2019-02-19
PlayerId: 1981654448 PlayerName: Player 35 Score: 929,003 Timestamp: 2019-02-22
PlayerId: 6968576389 PlayerName: Player 40 Score: 898,041 Timestamp: 2019-02-21
PlayerId: 9395039625 PlayerName: Player 59 Score: 849,955 Timestamp: 2019-02-21
PlayerId: 5954045812 PlayerName: Player 8 Score: 795,639 Timestamp: 2019-02-22
PlayerId: 3889939638 PlayerName: Player 71 Score: 775,252 Timestamp: 2019-02-21
PlayerId: 5529627211 PlayerName: Player 16 Score: 604,695 Timestamp: 2019-02-19
PlayerId: 9006728426 PlayerName: Player 3 Score: 457,208 Timestamp: 2019-02-22
PlayerId: 8289497066 PlayerName: Player 58 Score: 227,697 Timestamp: 2019-02-20
PlayerId: 8065482904 PlayerName: Player 99 Score: 198,429 Timestamp: 2019-02-24
کار عالی!
اکنون همانطور که رکوردها را اضافه می کنید، Cloud Spanner پایگاه داده شما را به هر اندازه که نیاز دارید مقیاس می دهد. مهم نیست که پایگاه داده شما چقدر رشد می کند، تابلوی امتیازات بازی شما می تواند با استفاده از Cloud Spanner و فناوری Truetime آن با دقت به مقیاس خود ادامه دهد.
7. پاکسازی
پس از همه سرگرمیهای بازی با Spanner، باید زمین بازی خود را تمیز کنیم و منابع و پول گرانبها را ذخیره کنیم. خوشبختانه این یک مرحله آسان است، کافی است به بخش Cloud Spanner در Cloud Console بروید و نمونهای را که در مرحله Codelab ایجاد کردیم به نام "Setup a Cloud Spanner Instance" را حذف کنید.
8. تبریک می گویم!
آنچه ما پوشش داده ایم:
- نمونههای Google Cloud Spanner، پایگاههای داده و جدول جدول برای تابلوی امتیازات
- نحوه ایجاد اپلیکیشن کنسول جاوا
- نحوه ایجاد یک پایگاه داده و جداول Spanner با استفاده از کتابخانه مشتری جاوا
- نحوه بارگذاری داده ها در پایگاه داده Spanner با استفاده از کتابخانه مشتری جاوا
- نحوه پرس و جو کردن نتایج "Top Ten" از داده های خود با استفاده از مهرهای زمانی commit Spanner و کتابخانه مشتری Java
مراحل بعدی:
- کاغذ سفید Spanner CAP را بخوانید
- درباره بهترین شیوه های طراحی طرحواره و پرس و جو بیاموزید
- درباره مهرهای زمانی commit Cloud Spanner بیشتر بیاموزید
نظرات خود را با ما در میان بگذارید
- لطفا یک لحظه برای تکمیل نظرسنجی بسیار کوتاه ما وقت بگذارید