Google Cloud Spanner adalah layanan database relasional skalabel dan terkelola sepenuhnya secara global yang menyediakan transaksi ACID dan semantik SQL tanpa merusak performa dan ketersediaan yang tinggi.
Di lab ini, Anda akan mempelajari cara menyiapkan instance Cloud Spanner. Anda akan menjalani langkah-langkah untuk membuat database dan skema yang dapat digunakan untuk papan peringkat game. Anda akan mulai dengan membuat tabel Pemain untuk menyimpan informasi pemain dan tabel Skor untuk menyimpan skor pemain.
Selanjutnya, Anda akan mengisi tabel dengan data contoh. Kemudian Anda akan mengakhiri lab dengan menjalankan kueri contoh Sepuluh Teratas dan menghapus instance untuk mengosongkan resource.
Yang akan Anda pelajari
- Cara menyiapkan instance Cloud Spanner.
- Cara membuat database dan tabel.
- Cara menggunakan kolom stempel waktu commit.
- Cara memuat data ke tabel database Cloud Spanner dengan stempel waktu.
- Cara membuat kueri database Cloud Spanner.
- Cara menghapus instance Cloud Spanner.
Yang akan Anda butuhkan
Bagaimana Anda akan menggunakan tutorial ini?
Bagaimana penilaian Anda terhadap pengalaman dengan Google Cloud Platform?
Penyiapan lingkungan mandiri
Jika belum memiliki Akun Google (Gmail atau Google Apps), Anda harus membuatnya. Login ke Google Cloud Platform console (console.cloud.google.com) dan buat project baru.
Jika Anda sudah memiliki project, klik menu pull-down pilihan project di kiri atas konsol:
dan klik tombol 'PROJECT BARU' dalam dialog yang dihasilkan untuk membuat project baru:
Jika belum memiliki project, Anda akan melihat dialog seperti ini untuk membuat project pertama:
Dialog pembuatan project berikutnya memungkinkan Anda memasukkan detail project baru:
Ingat project ID yang merupakan nama unik di semua project Google Cloud (maaf, nama di atas telah digunakan dan tidak akan berfungsi untuk Anda!) Project ID tersebut selanjutnya akan dirujuk di codelab ini sebagai PROJECT_ID
.
Selanjutnya, jika Anda belum melakukannya, Anda harus mengaktifkan penagihan di Developers Console untuk menggunakan resource Google Cloud dan mengaktifkan Cloud Spanner API.
Menjalankan melalui codelab ini tidak akan menghabiskan biaya lebih dari beberapa dolar, tetapi bisa lebih jika Anda memutuskan untuk menggunakan lebih banyak resource atau jika Anda membiarkannya berjalan (lihat bagian "pembersihan" di akhir dokumen ini). Harga Google Cloud Spanner didokumentasikan di sini.
Pengguna baru Google Cloud Platform memenuhi syarat untuk mendapatkan uji coba gratis senilai $300, yang menjadikan codelab ini sepenuhnya gratis.
Penyiapan Google Cloud Shell
Meskipun Google Cloud dan Spanner dapat dioperasikan dari jarak jauh menggunakan laptop Anda, dalam codelab ini, kita akan menggunakan Google Cloud Shell, lingkungan command line yang berjalan di Cloud.
Mesin virtual berbasis Debian ini memuat semua alat pengembangan yang akan Anda perlukan. Layanan ini menawarkan direktori beranda tetap sebesar 5 GB dan beroperasi di Google Cloud, sehingga sangat meningkatkan performa dan autentikasi jaringan. Ini berarti bahwa semua yang Anda perlukan untuk codelab ini adalah browser (ya, ini berfungsi di Chromebook).
- Untuk mengaktifkan Cloud Shell dari Cloud Console, cukup klik Aktifkan Cloud Shell (hanya perlu beberapa saat untuk melakukan penyediaan dan terhubung ke lingkungan).
Setelah terhubung ke Cloud Shell, Anda akan melihat bahwa Anda sudah diautentikasi dan project sudah ditetapkan ke PROJECT_ID
.
gcloud auth list
Output perintah
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Output perintah
[core] project = <PROJECT_ID>
Jika, untuk beberapa alasan, project belum disetel, cukup jalankan perintah berikut:
gcloud config set project <PROJECT_ID>
Mencari PROJECT_ID
Anda? Periksa ID yang Anda gunakan di langkah-langkah penyiapan atau cari di dasbor Cloud Console:
Cloud Shell juga menetapkan beberapa variabel lingkungan secara default, yang mungkin berguna saat Anda menjalankan perintah di masa mendatang.
echo $GOOGLE_CLOUD_PROJECT
Output perintah
<PROJECT_ID>
- Terakhir, tetapkan zona dan konfigurasi project default.
gcloud config set compute/zone us-central1-f
Anda dapat memilih berbagai zona yang berbeda. Untuk informasi selengkapnya, lihat Region & Zona.
Ringkasan
Pada langkah ini, Anda menyiapkan lingkungan.
Berikutnya
Selanjutnya, Anda akan menyiapkan Instance Cloud Spanner.
Pada langkah ini kita menyiapkan Instance Cloud Spanner untuk codelab ini. Telusuri entri Spanner di kiri atas Menu Tiga Garis atau telusuri Spanner dengan menekan "/" dan ketik "Spanner"
Selanjutnya, klik dan isi formulir dengan memasukkan nama instance cloudspanner-leaderboard untuk instance Anda, memilih konfigurasi (pilih instance regional), dan menetapkan jumlah node, untuk codelab ini kita hanya perlu 1 node. Agar instance produksi dan untuk memenuhi syarat untuk SLA Cloud Spanner, Anda harus menjalankan 3 node atau lebih di instance Cloud Spanner.
Terakhir, namun tidak kalah penting, klik "Buat" dan dalam beberapa detik Anda sudah memiliki instance Cloud Spanner.
Pada langkah berikutnya, kita akan menggunakan library klien Java untuk membuat database dan skema dalam instance baru.
Pada langkah ini, kita akan membuat contoh database dan skema.
Mari menggunakan library klien Java untuk membuat dua tabel; tabel Pemain untuk info pemain dan tabel Skor untuk menyimpan skor pemain. Untuk melakukannya, kita akan memandu langkah-langkah pembuatan aplikasi konsol Java di Cloud Shell.
Pertama-tama, clone kode sampel untuk codelab ini dari GitHub dengan mengetik perintah berikut di Cloud Shell:
git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git
Kemudian, ubah direktori ke direktori "aplikasi" tempat Anda akan membuat aplikasi.
cd java-docs-samples/spanner/leaderboard
Semua kode yang diperlukan untuk codelab ini terletak di direktori java-docs-samples/spanner/leaderboard/complete
yang ada sebagai aplikasi Go yaC# dapat dijalankan dengan nama Leaderboard
untuk berfungsi sebagai referensi saat Anda melanjutkan codelab. Kami akan membuat direktori baru dan mem-build salinan aplikasi Papan Peringkat secara bertahap.
Buat direktori baru bernama "codelab" untuk aplikasi dan ubah direktori menjadi papan peringkat dengan perintah berikut:
mkdir codelab && cd $_
Buat aplikasi Java dasar baru bernama "Leaderboard" menggunakan perintah Maven (mvn) berikut:
mvn -B archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=com.google.codelabs -DartifactId=leaderboard -DarchetypeVersion=1.4
Perintah ini membuat aplikasi konsol sederhana yang terdiri dari dua file utama, yakni file konfigurasi aplikasi Maven pom.xml
dan file aplikasi Java App.java
.
Selanjutnya, ubah direktori menjadi direktori papan peringkat yang baru saja dibuat dan masukkan daftar kontennya:
cd leaderboard && ls
Anda akan melihat file pom.xml
dan direktori src
tercantum:
pom.xml src
Sekarang mari kita update aplikasi konsol ini dengan mengedit App.java
untuk menggunakan library klien Java Spanner untuk membuat papan peringkat yang terdiri dari dua tabel, yakni tabel Pemain dan tabel Skor. Anda dapat melakukannya langsung di Cloud Shell Editor:
Buka Cloud Shell Editor, dengan mengklik ikon yang disorot di bawah:
Buka pom.xml di bawah folder papan peringkat. Buka file pom.xml yang ada di folder java-docs-samples\ spanner\leaderboard\codelab\leaderboard
. File ini mengonfigurasi sistem build maven untuk membuild aplikasi ke dalam satu jar, termasuk semua dependensi.
Tambahkan 1 bagian pengelolaan dependensi baru tepat di bawah elemen </properties> yang ada:
<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>
Tambahkan juga 1 dependensi baru di bagian <dependencies> yang ada, yang akan menambahkan library klien Java Cloud Spanner ke aplikasi.
<dependency>
<!-- Version auto-managed by BOM -->
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner</artifactId>
</dependency>
Kemudian ganti bagian <build> yang sudah ada pada file pom.xml
dengan bagian <build> berikut:
<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>
Simpan perubahan yang Anda buat pada file pom.xml dengan memilih "Simpan" di bawah menu "File" pada Cloud Shell Editor atau dengan menekan tombol keyboard "Ctrl" dan "S" secara bersamaan.
Selanjutnya, buka file App.java
di Cloud Shell Editor yang ada di folder src/main/java/com/google/codelabs/
. Ganti kode yang ada pada file dengan kode yang diperlukan untuk membuat database leaderboard
serta tabel Players
dan Scores
dengan menempelkan kode Java berikut ke dalam file App.java
:
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");
}
}
Simpan perubahan yang Anda buat ke file App.java
dengan memilih "Simpan" di bagian menu "File" pada Cloud Shell Editor.
Anda dapat menggunakan file App.java
di direktori java-docs-samples/spanner/leaderboard/step4/src
untuk melihat contoh tampilan file App.java
setelah menambahkan kode untuk mengaktifkan perintah create
.
Untuk membuild aplikasi Anda agar menjalankan paket mvn dari direktori tempat pom.xml
Anda berada:
mvn package
Setelah file Java jar berhasil dibuat, jalankan aplikasi yang dihasilkan dalam Cloud Shell dengan memasukkan perintah berikut:
java -jar target/leaderboard.jar
Anda akan melihat output seperti berikut:
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.
Dari respons ini, kita dapat melihat bahwa ini adalah aplikasi Leaderboard
yang saat ini memiliki satu kemungkinan perintah: create
. Kita dapat melihat bahwa argumen yang diharapkan dari perintah create
adalah ID Instance dan ID Database.
Sekarang jalankan perintah berikut.
java -jar target/leaderboard.jar create cloudspanner-leaderboard leaderboard
Setelah beberapa detik, Anda akan melihat respons seperti berikut:
Created database [projects/your-project/instances/cloudspanner-leaderboard/databases/leaderboard]
Di bagian Cloud Spanner pada Cloud Console, Anda akan melihat database dan tabel baru muncul di menu sebelah kiri.
Pada langkah berikutnya, kita akan mengupdate aplikasi untuk memuat beberapa data ke database baru Anda.
Sekarang kita memiliki database yang disebut leaderboard
yang berisi dua tabel; Players
dan Scores
Sekarang mari kita gunakan library klien Java untuk mengisi tabel Players
dengan pemain dan tabel Scores
dengan skor acak untuk setiap pemain.
Jika belum terbuka, buka Cloud Shell Editor dengan mengklik ikon yang ditandai di bawah:
Selanjutnya, edit file App.java
di Cloud Shell Editor untuk menambahkan perintah insert
yang dapat digunakan untuk menyisipkan 100 pemain ke dalam tabel Players
atau dapat digunakan untuk menyisipkan 4 skor acak di tabel Scores
untuk setiap pemain di tabel Players
.
Pertama-tama update bagian imports
di bagian atas file aplikasi, menggantikan apa yang saat ini ada, sehingga setelah selesai akan terlihat seperti berikut:
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;
Selanjutnya, tambahkan metode insert, insertPlayers, dan insertScores berikut di bawah metode create()
yang ada dan di atas metode printUsageAndExit()
yang ada:
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...");
}
}
Kemudian, untuk membuat perintah insert
berfungsi, tambahkan kode berikut ke metode "utama" aplikasi Anda dalam pernyataan switch (command)
:
case "insert":
String insertType;
try {
insertType = args[3];
} catch (ArrayIndexOutOfBoundsException exception) {
insertType = "";
}
insert(dbClient, insertType);
break;
Setelah Anda selesai, pernyataan switch (command)
akan terlihat seperti berikut:
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();
}
Langkah terakhir untuk menyelesaikan penambahan fungsi "insert" ke aplikasi Anda adalah menambahkan teks bantuan untuk perintah "insert" ke metode printUsageAndExit()
. Tambahkan baris kode berikut ke metode printUsageAndExit()
untuk menyertakan teks bantuan untuk perintah 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");
Simpan perubahan yang Anda buat ke file App.java
dengan memilih "Simpan" di bagian menu "File" pada Cloud Shell Editor.
Anda dapat menggunakan file App.java
di direktori java-docs-samples/spanner/leaderboard/step5/src
untuk melihat contoh tampilan file App.java
setelah menambahkan kode untuk mengaktifkan perintah insert
.
Sekarang mari kita buat ulang dan jalankan aplikasi untuk mengonfirmasi bahwa perintah insert
baru disertakan dalam daftar kemungkinan perintah aplikasi.
Untuk membuat aplikasi Anda, jalankan mvn package
dari direktori tempat pom.xml berada:
mvn package
Setelah file Java jar Anda berhasil dibuat, jalankan perintah berikut:
java -jar target/leaderboard.jar
Anda akan melihat perintah insert
sekarang disertakan dalam output default aplikasi:
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.
Anda bisa melihat dari respons bahwa selain ID Instance dan ID Database, ada argumen lain yang bisa memiliki nilai 'pemain' atau 'skor'.
Sekarang, mari kita jalankan perintah insert
dengan nilai argumen yang sama dengan yang digunakan saat kita memanggil perintah create
, menambahkan "pemain" sebagai argumen "type of insert" tambahan.
java -jar target/leaderboard.jar insert cloudspanner-leaderboard leaderboard players
Setelah beberapa detik, Anda akan melihat respons seperti berikut:
Done inserting player records...
Sekarang mari kita gunakan library klien Java untuk mengisi tabel Scores
dengan empat skor acak beserta stempel waktu untuk setiap pemain di tabel Players
.
Kolom Timestamp
pada tabel Scores
ditetapkan sebagai kolom "stempel waktu commit" melalui pernyataan SQL berikut yang dijalankan saat sebelumnya menjalankan perintah 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
Perhatikan atribut OPTIONS(allow_commit_timestamp=true)
. Ini membuat Timestamp
menjadi kolom "stempel waktu commit" dan mengaktifkannya untuk diisi secara otomatis dengan stempel waktu transaksi yang tepat untuk operasi INSERT dan UPDATE pada baris tabel tertentu.
Anda juga dapat menyisipkan nilai stempel waktu Anda sendiri ke dalam kolom "stempel waktu commit" selama Anda menyisipkan stempel waktu dengan nilai yang sudah berlalu, yang akan kita lakukan untuk tujuan codelab ini.
Sekarang, mari kita jalankan perintah insert
dengan nilai argumen yang sama dengan yang digunakan saat kita memanggil perintah create
, menambahkan "skor" sebagai argumen "type of insert" tambahan.
java -jar target/leaderboard.jar insert cloudspanner-leaderboard leaderboard scores
Setelah beberapa detik, Anda akan melihat respons seperti berikut:
Done inserting score records...
Menjalankan insert
dengan "type of insert" yang ditentukan sebagai scores
memanggil metode insertScores
yang menggunakan cuplikan kode berikut untuk menyisipkan stempel waktu yang dibuat secara acak dengan tanggal-waktu yang terjadi di waktu lampau:
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())
Untuk mengisi kolom Timestamp
secara otomatis dengan stempel waktu tepat saat transaksi "Insert" terjadi, Anda dapat menyisipkan konstanta Java Value.COMMIT_TIMESTAMP
seperti dalam cuplikan kode berikut:
.bind("Timestamp")
.to(Value.COMMIT_TIMESTAMP)
Setelah menyelesaikan pemuatan data, mari kita verifikasi nilai yang baru saja kita tulis ke tabel baru. Pertama-tama, pilih database leaderboard
, lalu pilih tabel Players
. Klik tab Data
. Anda akan melihat bahwa Anda memiliki data di kolom PlayerId
dan PlayerName
tabel.
Selanjutnya, pastikan tabel Skor juga memiliki data dengan mengklik tabel Scores
dan memilih tab Data
. Anda akan melihat bahwa Anda memiliki data di kolom PlayerId
, Timestamp
, dan Score
tabel.
Bagus! Mari mengupdate aplikasi untuk menjalankan beberapa kueri yang dapat kita gunakan untuk membuat papan peringkat game.
Setelah menyiapkan database dan memuat informasi ke dalam tabel, mari kita buat papan peringkat menggunakan data ini. Untuk melakukannya, kita harus menjawab empat pertanyaan berikut:
- Pemain mana yang masuk peringkat "Sepuluh Teratas" sepanjang waktu?
- Pemain mana yang masuk peringkat "Sepuluh Teratas" tahun ini?
- Pemain mana yang masuk peringkat "Sepuluh Teratas" bulan ini?
- Pemain mana yang masuk peringkat "Sepuluh Teratas" minggu ini?
Mari mengupdate aplikasi untuk menjalankan kueri SQL yang akan menjawab pertanyaan ini.
Kita akan menambahkan perintah query
yang akan memberikan cara untuk menjalankan kueri guna menjawab pertanyaan yang akan menghasilkan informasi yang diperlukan untuk papan peringkat.
Edit file App.java
dalam Cloud Shell Editor untuk mengupdate aplikasi guna menambahkan perintah query
. Perintah query
terdiri dari dua metode query
, salah satunya hanya memerlukan argumen DatabaseClient
dan satu lainnya membutuhkan argumen timespan
tambahan untuk memfasilitasi pemfilteran hasil berdasarkan rentang waktu yang ditentukan dalam jam.
Tambahkan dua metode query
berikut di bawah metode insertScores()
yang ada dan di atas metode printUsageAndExit()
yang ada:
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));
}
}
Kemudian, untuk membuat perintah query
berfungsi, tambahkan kode berikut ke pernyataan switch(command)
dalam metode "utama" aplikasi:
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;
Langkah terakhir untuk menyelesaikan penambahan fungsi "kueri" ke aplikasi Anda adalah menambahkan teks bantuan untuk perintah "kueri" ke metode printUsageAndExit()
. Tambahkan baris kode berikut ke metode printUsageAndExit()
untuk menyertakan teks bantuan untuk perintah "kueri":
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");
Simpan perubahan yang Anda buat ke file App.java
dengan memilih "Simpan" di bagian menu "File" pada Cloud Shell Editor.
Anda dapat menggunakan file App.java
di direktori dotnet-docs-samples/applications/leaderboard/step6/src
untuk melihat contoh tampilan file App.java
setelah menambahkan kode untuk mengaktifkan perintah query
.
Untuk membuat aplikasi Anda, jalankan mvn package
dari direktori tempat pom.xml berada:
mvn package
Sekarang mari kita jalankan aplikasi untuk mengonfirmasi bahwa perintah query
baru disertakan dalam daftar kemungkinan perintah aplikasi. Jalankan perintah berikut:
java -jar target/leaderboard.jar
Anda akan melihat perintah query
kini disertakan dalam output default aplikasi sebagai opsi perintah baru:
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.
Anda dapat melihat dari respons bahwa selain argumen ID Instance dan ID Database, perintah query
memungkinkan kita menentukan rentang waktu opsional dalam jumlah jam yang akan digunakan untuk memfilter data berdasarkan nilainya di kolom Timestamp
pada tabel Scores
. Karena argumen rentang waktu bersifat opsional, ini berarti bahwa jika argumen rentang waktu tersebut tidak disertakan, tidak ada data yang akan difilter menurut stempel waktu. Jadi kita bisa menggunakan perintah query
tanpa nilai "timespan" untuk mendapatkan daftar pemain "Sepuluh Teratas" sepanjang masa.
Mari kita jalankan perintah query
tanpa menetapkan "timespan", menggunakan nilai argumen yang sama dengan yang digunakan saat menjalankan perintah create
.
java -jar target/leaderboard.jar query cloudspanner-leaderboard leaderboard
Anda akan melihat respons yang menyertakan pemain "Sepuluh Teratas" sepanjang masa seperti berikut:
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
Sekarang mari kita jalankan perintah query
dengan argumen yang diperlukan untuk membuat kueri pemain "Sepuluh Teratas" tahun ini dengan menentukan "timespan" yang sama dengan jumlah jam dalam setahun, yakni 8.760.
java -jar target/leaderboard.jar query cloudspanner-leaderboard leaderboard 8760
Anda akan melihat respons yang menyertakan pemain "Sepuluh Teratas" tahun ini seperti berikut:
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
Sekarang, mari kita jalankan perintah query
untuk membuat kueri pemain "Sepuluh Teratas" bulan ini dengan menentukan "timespan" yang sama dengan jumlah jam dalam sebulan, yaitu 730.
java -jar target/leaderboard.jar query cloudspanner-leaderboard leaderboard 730
Anda akan melihat respons yang menyertakan pemain "Sepuluh Teratas" bulan ini seperti berikut:
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
Sekarang mari kita jalankan perintah query
untuk membuat kueri pemain "Sepuluh Teratas" minggu ini dengan menetapkan "timespan" yang sama dengan jumlah jam dalam seminggu, yaitu 168.
java -jar target/leaderboard.jar query cloudspanner-leaderboard leaderboard 168
Anda akan melihat respons yang menyertakan pemain "Sepuluh Teratas" minggu ini seperti berikut:
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
Bagus!
Kini setelah Anda menambahkan data, Cloud Spanner akan mengubah skala database Anda menjadi sebesar apa pun kebutuhan Anda. Berapa pun pertumbuhan database Anda, papan peringkat game dapat terus diskalakan dengan akurat menggunakan Cloud Spanner dan teknologi Truetime-nya.
Setelah asyik bermain dengan Spanner, kita perlu membersihkan tempat bermain kita, menghemat resource dan uang yang berharga. Untungnya ini adalah langkah yang mudah. Cukup buka bagian Cloud Spanner dari Cloud Console dan hapus instance yang kita buat di langkah codelab bernama "Siapkan Instance Cloud Spanner".
Yang telah kita bahas:
- Instance, Database, dan Skema Tabel Google Cloud Spanner untuk papan peringkat
- Cara membuat aplikasi konsol Java
- Cara membuat Database Spanner dan Tabel menggunakan library klien Java
- Cara memuat data ke dalam Database Spanner menggunakan library klien Java
- Cara membuat kueri hasil "Sepuluh Teratas" dari data Anda menggunakan stempel waktu commit Spanner dan library klien Java
Langkah Berikutnya:
- Baca Laporan resmi Spanner CAP
- Pelajari tentang Desain Skema dan Praktik terbaik kueri
- Pelajari lebih lanjut stempel waktu commit Cloud Spanner
Kirimkan masukan Anda
- Luangkan waktu Anda untuk menyelesaikan survei singkat kami