1. Genel Bakış
Google Cloud Spanner, performanstan ve yüksek kullanılabilirlikten ödün vermeden ACID işlemleri ve SQL semantiği sağlayan, tümüyle yönetilen, yatay olarak ölçeklenebilir, küresel olarak dağıtılmış bir ilişkisel veritabanı hizmetidir.
Bu laboratuvarda, Cloud Spanner örneği oluşturmayı öğreneceksiniz. Oyunlardaki skor tablosu için kullanılabilecek bir veritabanı ve şema oluşturma adımlarını inceleyeceksiniz. Oyuncu bilgilerini depolamak için bir Oyuncular tablosu ve oyuncu puanlarını depolamak için bir Puanlar tablosu oluşturarak başlayacaksınız.
Ardından, tabloları örnek verilerle doldurursunuz. Ardından, bazı İlk On örnek sorgularını çalıştırarak laboratuvarı tamamlayacak ve kaynakları boşaltmak için örneği sileceksiniz.
Neler öğreneceksiniz?
- Cloud Spanner örneği oluşturma
- Veritabanı ve tablolar oluşturma
- Commit zaman damgası sütunu nasıl kullanılır?
- Zaman damgalarıyla Cloud Spanner veritabanı tablonuza veri yükleme
- Cloud Spanner veritabanınızı sorgulama
- Cloud Spanner örneğinizi nasıl sileceğiniz açıklanır.
İhtiyacınız olanlar
Bu eğitimi nasıl kullanacaksınız?
Google Cloud Platform deneyiminizi nasıl değerlendirirsiniz?
2. Kurulum ve Gereksinimler
Yönlendirmesiz ortam kurulumu
Google Hesabınız (Gmail veya Google Apps) yoksa hesap oluşturmanız gerekir. Google Cloud Platform Console'da ( console.cloud.google.com) oturum açın ve yeni bir proje oluşturun.
Önceden oluşturduğunuz bir projeniz varsa konsolun sol üst kısmındaki proje seçimi açılır menüsünü tıklayın:

ve yeni bir proje oluşturmak için açılan iletişim kutusunda "YENİ PROJE" düğmesini tıklayın:

Henüz bir projeniz yoksa ilk projenizi oluşturmak için aşağıdaki gibi bir iletişim kutusu görürsünüz:

Sonraki proje oluşturma iletişim kutusunda yeni projenizin ayrıntılarını girebilirsiniz:

Tüm Google Cloud projelerinde benzersiz bir ad olan proje kimliğini unutmayın (Yukarıdaki ad zaten alınmış olduğundan sizin için çalışmayacaktır). Bu codelab'in ilerleyen kısımlarında PROJECT_ID olarak adlandırılacaktır.
Ardından, henüz yapmadıysanız Google Cloud kaynaklarını kullanmak için Developers Console'da faturalandırmayı etkinleştirmeniz ve Cloud Spanner API'yi etkinleştirmeniz gerekir.

Bu codelab'i tamamlamak size birkaç dolardan fazla maliyet getirmemelidir. Ancak daha fazla kaynak kullanmaya veya kaynakları çalışır durumda bırakmaya karar verirseniz maliyet artabilir (bu belgenin sonundaki "temizleme" bölümüne bakın). Google Cloud Spanner fiyatlandırması burada belgelenmiştir.
Google Cloud Platform'un yeni kullanıcıları, bu codelab'i tamamen ücretsiz hale getirecek 300 ABD doları değerinde ücretsiz deneme sürümünden yararlanabilir.
Google Cloud Shell Kurulumu
Google Cloud ve Spanner, dizüstü bilgisayarınızdan uzaktan çalıştırılabilir ancak bu codelab'de Cloud'da çalışan bir komut satırı ortamı olan Google Cloud Shell'i kullanacağız.
Bu Debian tabanlı sanal makine, ihtiyaç duyacağınız tüm geliştirme araçlarını içerir. 5 GB boyutunda kalıcı bir ana dizin bulunur ve Google Cloud'da çalışır. Bu sayede ağ performansı ve kimlik doğrulama önemli ölçüde güçlenir. Bu nedenle, bu codelab için ihtiyacınız olan tek şey bir tarayıcıdır (Chromebook'ta da çalışır).
- Cloud Shell'i Cloud Console'dan etkinleştirmek için Cloud Shell'i etkinleştir 'i
tıklamanız yeterlidir (ortamın sağlanması ve bağlantının kurulması yalnızca birkaç saniye sürer).
Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin, PROJECT_ID'nize ayarlandığını görürsünüz.
gcloud auth list
Komut çıkışı
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Komut çıkışı
[core] project = <PROJECT_ID>
Herhangi bir nedenle proje ayarlanmamışsa şu komutu verin:
gcloud config set project <PROJECT_ID>
PROJECT_ID cihazınızı mı arıyorsunuz? Kurulum adımlarında hangi kimliği kullandığınızı kontrol edin veya Cloud Console kontrol panelinde arayın:
Cloud Shell, gelecekteki komutları çalıştırırken faydalı olabilecek bazı ortam değişkenlerini de varsayılan olarak ayarlar.
echo $GOOGLE_CLOUD_PROJECT
Komut çıkışı
<PROJECT_ID>
- Son olarak, varsayılan alt bölgeyi ve proje yapılandırmasını ayarlayın.
gcloud config set compute/zone us-central1-f
Çeşitli bölgeler arasından seçim yapabilirsiniz. Daha fazla bilgi için Bölgeler ve Alt Bölgeler başlıklı makaleyi inceleyin.
Özet
Bu adımda ortamınızı ayarlarsınız.
Sıradaki
Ardından, Cloud Spanner örneği oluşturacaksınız.
3. Cloud Spanner örneği oluşturma
Bu adımda, bu codelab için Cloud Spanner örneğimizi kuruyoruz. Sol üstteki hamburger menüsünde
Spanner girişini arayın
veya "/" tuşuna basıp "Spanner" yazarak Spanner'ı arayın.

Ardından
simgesini tıklayın ve örneğiniz için cloudspanner-leaderboard örnek adını girerek, bir yapılandırma seçerek (bölgesel bir örnek seçin) ve düğüm sayısını ayarlayarak formu doldurun. Bu codelab için yalnızca 1 düğüme ihtiyacımız olacak. Üretim örnekleri için ve Cloud Spanner HDS'sine uygun olmak üzere Cloud Spanner örneğinizde 3 veya daha fazla düğüm çalıştırmanız gerekir.
Son olarak "Oluştur"u tıkladığınızda saniyeler içinde Cloud Spanner örneğini kullanmaya başlayabilirsiniz.

Bir sonraki adımda, yeni örneğimizde veritabanı ve şema oluşturmak için C# istemci kitaplığını kullanacağız.
4. Veritabanı ve şema oluşturma
Bu adımda örnek veritabanımızı ve şemamızı oluşturacağız.
Oyuncu bilgileri için bir Oyuncular tablosu ve oyuncu puanlarını depolamak için bir Puanlar tablosu olmak üzere iki tablo oluşturmak için C# istemci kitaplığını kullanalım. Bunu yapmak için Cloud Shell'de C# konsol uygulaması oluşturma adımlarını inceleyeceğiz.
Öncelikle Cloud Shell'de aşağıdaki komutu yazarak bu codelab'in örnek kodunu GitHub'dan klonlayın:
git clone https://github.com/GoogleCloudPlatform/dotnet-docs-samples.git
Ardından, uygulamanızı oluşturacağınız "applications" dizinine geçin.
cd dotnet-docs-samples/applications/
Bu codelab için gereken tüm kod, codelab'de ilerlerken referans olarak kullanabileceğiniz, dotnet-docs-samples/applications/leaderboard dizininde Leaderboard adlı çalıştırılabilir bir C# uygulaması olarak bulunur. Yeni bir dizin oluşturup skor tablosu uygulamasının bir kopyasını aşamalar halinde oluşturacağız.
Uygulama için "codelab" adlı yeni bir dizin oluşturun ve aşağıdaki komutla dizini değiştirin:
mkdir codelab && cd $_
Aşağıdaki komutu kullanarak "Leaderboard" adlı yeni bir .NET C# konsol uygulaması oluşturun:
dotnet new console -n Leaderboard
Bu komut, iki temel dosyadan oluşan basit bir konsol uygulaması oluşturur: proje dosyası Leaderboard.csproj ve program dosyası Program.cs.
Çalıştıralım. Dizini, uygulamanın bulunduğu yeni oluşturulan skor tablosu dizini olarak değiştirin:
cd Leaderboard
Ardından, çalıştırmak için aşağıdaki komutu girin.
dotnet run
"Hello World!" uygulama çıkışını görürsünüz.
Şimdi de Program.cs dosyasını düzenleyerek konsol uygulamamızı güncelleyelim. Bu işlemde, iki tablodan (Oyuncular ve Puanlar) oluşan bir skor tablosu oluşturmak için C# Spanner istemci kitaplığını kullanacağız. Bunu doğrudan Cloud Shell Düzenleyici'de yapabilirsiniz:
Aşağıda vurgulanan simgeyi tıklayarak Cloud Shell Düzenleyici'yi açın:

Ardından, Cloud Shell Düzenleyici'de Program.cs dosyasını açın ve aşağıdaki C# uygulama kodunu Program.cs dosyasına yapıştırarak dosyanın mevcut kodunu leaderboard veritabanını, Players ve Scores tablolarını oluşturmak için gereken kodla değiştirin:
using System;
using System.Threading.Tasks;
using Google.Cloud.Spanner.Data;
using CommandLine;
namespace GoogleCloudSamples.Leaderboard
{
[Verb("create", HelpText = "Create a sample Cloud Spanner database "
+ "along with sample 'Players' and 'Scores' tables in your project.")]
class CreateOptions
{
[Value(0, HelpText = "The project ID of the project to use "
+ "when creating Cloud Spanner resources.", Required = true)]
public string projectId { get; set; }
[Value(1, HelpText = "The ID of the instance where the sample database "
+ "will be created.", Required = true)]
public string instanceId { get; set; }
[Value(2, HelpText = "The ID of the sample database to create.",
Required = true)]
public string databaseId { get; set; }
}
public class Program
{
enum ExitCode : int
{
Success = 0,
InvalidParameter = 1,
}
public static object Create(string projectId,
string instanceId, string databaseId)
{
var response =
CreateAsync(projectId, instanceId, databaseId);
Console.WriteLine("Waiting for operation to complete...");
response.Wait();
Console.WriteLine($"Operation status: {response.Status}");
Console.WriteLine($"Created sample database {databaseId} on "
+ $"instance {instanceId}");
return ExitCode.Success;
}
public static async Task CreateAsync(
string projectId, string instanceId, string databaseId)
{
// Initialize request connection string for database creation.
string connectionString =
$"Data Source=projects/{projectId}/instances/{instanceId}";
using (var connection = new SpannerConnection(connectionString))
{
string createStatement = $"CREATE DATABASE `{databaseId}`";
string[] createTableStatements = new string[] {
// Define create table statement for Players table.
@"CREATE TABLE Players(
PlayerId INT64 NOT NULL,
PlayerName STRING(2048) NOT NULL
) PRIMARY KEY(PlayerId)",
// Define create table statement for Scores table.
@"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" };
// Make the request.
var cmd = connection.CreateDdlCommand(
createStatement, createTableStatements);
try
{
await cmd.ExecuteNonQueryAsync();
}
catch (SpannerException e) when
(e.ErrorCode == ErrorCode.AlreadyExists)
{
// OK.
}
}
}
public static int Main(string[] args)
{
var verbMap = new VerbMap<object>();
verbMap
.Add((CreateOptions opts) => Create(
opts.projectId, opts.instanceId, opts.databaseId))
.NotParsedFunc = (err) => 1;
return (int)verbMap.Run(args);
}
}
}
Program kodunun daha net bir resmini sunmak için, önemli bileşenleri etiketlenmiş bir Program şeması aşağıda verilmiştir:

create komutunu etkinleştirmek için kodu ekledikten sonra Program.cs dosyanızın nasıl görünmesi gerektiğine dair bir örnek görmek için dotnet-docs-samples/applications/leaderboard/step4 dizinindeki Program.cs dosyasını kullanabilirsiniz.
Ardından, Cloud Shell Düzenleyici'yi kullanarak Program'ın proje dosyasını Leaderboard.csproj açıp düzenleyin ve aşağıdaki koda benzeyecek şekilde güncelleyin. Cloud Shell Düzenleyici'nin "Dosya" menüsünü kullanarak tüm değişikliklerinizi kaydettiğinizden emin olun.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Cloud.Spanner.Data" Version="3.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\commandlineutil\Lib\CommandLineUtil.csproj" />
</ItemGroup>
</Project>
Bu değişiklikle, Cloud Spanner API ile etkileşim kurmak için gereken C# Spanner Nuget paketine Google.Cloud.Spanner.Data referans eklendi. Bu değişiklik, dotnet-doc-samples GitHub deposunun bir parçası olan CommandLineUtil projesine bir referans da ekler ve açık kaynaklı CommandLineParser için yararlı bir "verbmap" uzantısı sağlar. Bu uzantı, konsol uygulamaları için komut satırı girişini işlemek üzere kullanılan kullanışlı bir kitaplıktır.
create komutunu etkinleştirmek için kodu ekledikten sonra Leaderboard.csproj dosyanızın nasıl görünmesi gerektiğine dair bir örnek görmek için dotnet-docs-samples/applications/leaderboard/step4 dizinindeki Leaderboard.csproj dosyasını kullanabilirsiniz.
Artık güncellenmiş örneğinizi çalıştırmaya hazırsınız. Güncellenen uygulamanızın varsayılan yanıtını görmek için aşağıdakileri yazın:
dotnet run
Aşağıdakine benzer bir çıkış alırsınız:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): No verb selected. create Create a sample Cloud Spanner database along with sample 'Players' and 'Scores' tables in your project. help Display more information on a specific command. version Display version information.
Bu yanıttan, Leaderboard uygulamasının create, help ve version olmak üzere üç olası komuttan biriyle çalıştırılabileceğini anlıyoruz.
Spanner veritabanı ve tabloları oluşturmak için create komutunu deneyelim. Komutun beklenen bağımsız değişkenlerini görmek için komutu bağımsız değişken olmadan çalıştırın.
dotnet run create
Aşağıdaki gibi bir yanıt görmeniz gerekir:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): A required value not bound to option name is missing. --help Display this help screen. --version Display version information. value pos. 0 Required. The project ID of the project to use when creating Cloud Spanner resources. value pos. 1 Required. The ID of the instance where the sample database will be created. value pos. 2 Required. The ID of the sample database to create.
Burada, create komutunun beklenen bağımsız değişkenlerinin proje kimliği, örnek kimliği ve veritabanı kimliği olduğunu görüyoruz.
Şimdi aşağıdaki komutu çalıştırın. PROJECT_ID yerine bu codelab'in başında oluşturduğunuz proje kimliğini yazdığınızdan emin olun.
dotnet run create PROJECT_ID cloudspanner-leaderboard leaderboard
Birkaç saniye sonra aşağıdaki gibi bir yanıt görmeniz gerekir:
Waiting for operation to complete... Operation status: RanToCompletion Created sample database leaderboard on instance cloudspanner-leaderboard
Cloud Console'un Cloud Spanner bölümünde, yeni veritabanınız ve tablolarınız sol taraftaki menüde görünür.

Bir sonraki adımda, uygulamanızı yeni veritabanınıza bazı veriler yükleyecek şekilde güncelleyeceğiz.
5. Verileri Yükle
Şimdi Players ve Scores olmak üzere iki tablo içeren leaderboard adlı bir veritabanımız var. Şimdi de C# istemci kitaplığını kullanarak Players tablomuzu oyuncularla, Scores tablomuzu ise her oyuncu için rastgele puanlarla dolduralım.
Aşağıda vurgulanan simgeyi tıklayarak Cloud Shell Düzenleyici'yi açın:

Ardından, Program.cs dosyasını Cloud Shell Düzenleyici'de düzenleyerek Players tablosuna 100 oyuncu eklemek için kullanılabilecek bir insert komutu ekleyin veya Players tablosundaki her oyuncu için Scores tablosuna 4 rastgele puan eklemek için kullanılabilecek bir komut ekleyin.
Öncelikle aşağıdaki Program'ın üst kısmındaki "Verbmap" bölümüne, mevcut create komut bloğunun altına yeni bir insert komut bloğu ekleyin:
[Verb("insert", HelpText = "Insert sample 'players' records or 'scores' records "
+ "into the database.")]
class InsertOptions
{
[Value(0, HelpText = "The project ID of the project to use "
+ "when managing Cloud Spanner resources.", Required = true)]
public string projectId { get; set; }
[Value(1, HelpText = "The ID of the instance where the sample database resides.",
Required = true)]
public string instanceId { get; set; }
[Value(2, HelpText = "The ID of the database where the sample database resides.",
Required = true)]
public string databaseId { get; set; }
[Value(3, HelpText = "The type of insert to perform, 'players' or 'scores'.",
Required = true)]
public string insertType { get; set; }
}
Ardından, mevcut CreateAsync yönteminin altına aşağıdaki Insert, InsertPlayersAsync ve InsertScoresAsync yöntemlerini ekleyin:
public static object Insert(string projectId,
string instanceId, string databaseId, string insertType)
{
if (insertType.ToLower() == "players")
{
var responseTask =
InsertPlayersAsync(projectId, instanceId, databaseId);
Console.WriteLine("Waiting for insert players operation to complete...");
responseTask.Wait();
Console.WriteLine($"Operation status: {responseTask.Status}");
}
else if (insertType.ToLower() == "scores")
{
var responseTask =
InsertScoresAsync(projectId, instanceId, databaseId);
Console.WriteLine("Waiting for insert scores operation to complete...");
responseTask.Wait();
Console.WriteLine($"Operation status: {responseTask.Status}");
}
else
{
Console.WriteLine("Invalid value for 'type of insert'. "
+ "Specify 'players' or 'scores'.");
return ExitCode.InvalidParameter;
}
Console.WriteLine($"Inserted {insertType} into sample database "
+ $"{databaseId} on instance {instanceId}");
return ExitCode.Success;
}
public static async Task InsertPlayersAsync(string projectId,
string instanceId, string databaseId)
{
string connectionString =
$"Data Source=projects/{projectId}/instances/{instanceId}"
+ $"/databases/{databaseId}";
long numberOfPlayers = 0;
using (var connection = new SpannerConnection(connectionString))
{
await connection.OpenAsync();
await connection.RunWithRetriableTransactionAsync(async (transaction) =>
{
// Execute a SQL statement to get current number of records
// in the Players table to use as an incrementing value
// for each PlayerName to be inserted.
var cmd = connection.CreateSelectCommand(
@"SELECT Count(PlayerId) as PlayerCount FROM Players");
numberOfPlayers = await cmd.ExecuteScalarAsync<long>();
// Insert 100 player records into the Players table.
SpannerBatchCommand cmdBatch = connection.CreateBatchDmlCommand();
for (int i = 0; i < 100; i++)
{
numberOfPlayers++;
SpannerCommand cmdInsert = connection.CreateDmlCommand(
"INSERT INTO Players "
+ "(PlayerId, PlayerName) "
+ "VALUES (@PlayerId, @PlayerName)",
new SpannerParameterCollection {
{"PlayerId", SpannerDbType.Int64},
{"PlayerName", SpannerDbType.String}});
cmdInsert.Parameters["PlayerId"].Value =
Math.Abs(Guid.NewGuid().GetHashCode());
cmdInsert.Parameters["PlayerName"].Value =
$"Player {numberOfPlayers}";
cmdBatch.Add(cmdInsert);
}
await cmdBatch.ExecuteNonQueryAsync();
});
}
Console.WriteLine("Done inserting player records...");
}
public static async Task InsertScoresAsync(
string projectId, string instanceId, string databaseId)
{
string connectionString =
$"Data Source=projects/{projectId}/instances/{instanceId}"
+ $"/databases/{databaseId}";
// Insert 4 score records into the Scores table for each player
// in the Players table.
using (var connection = new SpannerConnection(connectionString))
{
await connection.OpenAsync();
await connection.RunWithRetriableTransactionAsync(async (transaction) =>
{
Random r = new Random();
bool playerRecordsFound = false;
SpannerBatchCommand cmdBatch =
connection.CreateBatchDmlCommand();
var cmdLookup =
connection.CreateSelectCommand("SELECT * FROM Players");
using (var reader = await cmdLookup.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
playerRecordsFound = true;
for (int i = 0; i < 4; i++)
{
DateTime randomTimestamp = DateTime.Now
.AddYears(r.Next(-2, 1))
.AddMonths(r.Next(-12, 1))
.AddDays(r.Next(-28, 0))
.AddHours(r.Next(-24, 0))
.AddSeconds(r.Next(-60, 0))
.AddMilliseconds(r.Next(-100000, 0));
SpannerCommand cmdInsert =
connection.CreateDmlCommand(
"INSERT INTO Scores "
+ "(PlayerId, Score, Timestamp) "
+ "VALUES (@PlayerId, @Score, @Timestamp)",
new SpannerParameterCollection {
{"PlayerId", SpannerDbType.Int64},
{"Score", SpannerDbType.Int64},
{"Timestamp",
SpannerDbType.Timestamp}});
cmdInsert.Parameters["PlayerId"].Value =
reader.GetFieldValue<int>("PlayerId");
cmdInsert.Parameters["Score"].Value =
r.Next(1000, 1000001);
cmdInsert.Parameters["Timestamp"].Value =
randomTimestamp.ToString("o");
cmdBatch.Add(cmdInsert);
}
}
if (!playerRecordsFound)
{
Console.WriteLine("Parameter 'scores' is invalid "
+ "since no player records currently exist. First "
+ "insert players then insert scores.");
Environment.Exit((int)ExitCode.InvalidParameter);
}
else
{
await cmdBatch.ExecuteNonQueryAsync();
Console.WriteLine(
"Done inserting score records..."
);
}
}
});
}
}
Ardından, insert komutunun çalışır hâle gelmesi için aşağıdaki kodu Program'ınızın "Main" yöntemine ekleyin:
.Add((InsertOptions opts) => Insert(
opts.projectId, opts.instanceId, opts.databaseId, opts.insertType))
insert komutunu etkinleştirmek için kodu ekledikten sonra Program.cs dosyanızın nasıl görünmesi gerektiğine dair bir örnek görmek için dotnet-docs-samples/applications/leaderboard/step5 dizinindeki Program.cs dosyasını kullanabilirsiniz.
Şimdi de yeni insert komutunun programın olası komutlar listesinde yer aldığını doğrulamak için programı çalıştıralım. Aşağıdaki komutu çalıştırın:
dotnet run
Artık programın varsayılan çıkışında insert komutunu görmeniz gerekir:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): No verb selected. create Create a sample Cloud Spanner database along with sample 'Players' and 'Scores' tables in your project. insert Insert sample 'players' records or 'scores' records into the database. help Display more information on a specific command. version Display version information.
Şimdi de giriş bağımsız değişkenlerini görmek için insert komutunu çalıştıralım. Aşağıdaki komutu girin.
dotnet run insert
Bu işlem aşağıdaki yanıtı döndürmelidir:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): A required value not bound to option name is missing. --help Display this help screen. --version Display version information. value pos. 0 Required. The project ID of the project to use when managing Cloud Spanner resources. value pos. 1 Required. The ID of the instance where the sample database resides. value pos. 2 Required. The ID of the database where the sample database resides. value pos. 3 Required. The type of insert to perform, 'players' or 'scores'.
Yanıtı incelediğinizde, proje kimliği, örnek kimliği ve veritabanı kimliğine ek olarak, gerçekleştirilecek "ekleme türü" olan başka bir value pos. 3 bağımsız değişkeninin beklendiğini görebilirsiniz. Bu bağımsız değişkenin değeri "players" veya "scores" olabilir.
Şimdi, insert komutunu çağırırken kullandığımız aynı bağımsız değişken değerleriyle insert komutunu çalıştıralım ve ek "ekleme türü" bağımsız değişkeni olarak "players"ı ekleyelim.create PROJECT_ID yerine bu codelab'in başında oluşturduğunuz proje kimliğini yazdığınızdan emin olun.
dotnet run insert PROJECT_ID cloudspanner-leaderboard leaderboard players
Birkaç saniye sonra aşağıdaki gibi bir yanıt görmeniz gerekir:
Waiting for insert players operation to complete... Done inserting player records... Operation status: RanToCompletion Inserted players into sample database leaderboard on instance cloudspanner-leaderboard
Şimdi de Scores tablomuzu, Players tablosundaki her oyuncu için zaman damgalarıyla birlikte dört rastgele puanla doldurmak üzere C# istemci kitaplığını kullanalım.
Scores tablosunun Timestamp sütunu, daha önce create komutunu çalıştırdığımızda yürütülen aşağıdaki SQL ifadesiyle "commit timestamp" sütunu olarak tanımlandı:
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) özelliğine dikkat edin. Bu, Timestamp sütununu "commit timestamp" sütunu yapar ve belirli bir tablo satırında INSERT ve UPDATE işlemleri için tam işlem zaman damgasıyla otomatik olarak doldurulmasını sağlar.
Geçmişte bir değere sahip bir zaman damgası eklediğiniz sürece "commit timestamp" sütununa kendi zaman damgası değerlerinizi de ekleyebilirsiniz. Bu codelab'in amacı doğrultusunda bu işlemi yapacağız.
Şimdi, insert komutunu çağırırken kullandığımız aynı bağımsız değişken değerleriyle insert komutunu çalıştıralım ve ek "ekleme türü" bağımsız değişkeni olarak "puanlar"ı ekleyelim.create PROJECT_ID yerine bu codelab'in başında oluşturduğunuz proje kimliğini yazdığınızdan emin olun.
dotnet run insert PROJECT_ID cloudspanner-leaderboard leaderboard scores
Birkaç saniye sonra aşağıdaki gibi bir yanıt görmeniz gerekir:
Waiting for insert players operation to complete... Done inserting player records... Operation status: RanToCompletion Inserted players into sample database leaderboard on instance cloudspanner-leaderboard
insert, "ekleme türü" scores olarak belirtilerek çalıştırıldığında, geçmişte gerçekleşen bir tarih-saat ile rastgele oluşturulmuş bir zaman damgası eklemek için aşağıdaki kod snippet'lerini kullanan InsertScoresAsync yöntemi çağrılır:
DateTime randomTimestamp = DateTime.Now
.AddYears(r.Next(-2, 1))
.AddMonths(r.Next(-12, 1))
.AddDays(r.Next(-28, 0))
.AddHours(r.Next(-24, 0))
.AddSeconds(r.Next(-60, 0))
.AddMilliseconds(r.Next(-100000, 0));
...
cmdInsert.Parameters["Timestamp"].Value = randomTimestamp.ToString("o");
Timestamp sütununu, "Ekle" işleminin tam olarak gerçekleştiği zaman damgasıyla otomatik olarak doldurmak için aşağıdaki kod snippet'inde olduğu gibi SpannerParameter.CommitTimestamp C# sabitini ekleyebilirsiniz:
cmd.Parameters["Timestamp"].Value = SpannerParameter.CommitTimestamp;
Veri yükleme işlemini tamamladığımıza göre, yeni tablolarımıza yazdığımız değerleri doğrulayalım. Önce leaderboard veritabanını, ardından Players tablosunu seçin. Data sekmesini tıklayın. Tablonun PlayerId ve PlayerName sütunlarında verilerinizin olduğunu görmelisiniz.

Ardından, Scores tablosunu tıklayıp Data sekmesini seçerek Puanlar tablosunda da veri olup olmadığını doğrulayalım. Tablonun PlayerId, Timestamp ve Score sütunlarında verilerinizin olduğunu görmelisiniz.

Tebrikler! Oyun skor tablosu oluşturmak için kullanabileceğimiz bazı sorguları çalıştırmak üzere programımızı güncelleyelim.
6. Skor tablosu sorguları çalıştırma
Veritabanımızı ayarlayıp tablolarımıza bilgi yüklediğimize göre şimdi bu verileri kullanarak bir skor tablosu oluşturalım. Bunu yapmak için aşağıdaki dört soruyu yanıtlamamız gerekiyor:
- Tüm zamanların "En İyi On" oyuncusu kimlerdir?
- Yılın "En İyi On" oyuncusu kimler?
- Ayın "En İyi On" Oyuncusu kimler?
- Haftanın "En İyi On" oyuncusu kimler?
Bu soruları yanıtlayacak SQL sorgularını çalıştırmak için programımızı güncelleyelim.
Soruları yanıtlamak için sorguları çalıştırmanın bir yolunu sağlayacak bir query komutu ekleyeceğiz. Bu komut, skor tablomuz için gereken bilgileri üretecek.
Programa query komutunu eklemek için Cloud Shell Düzenleyici'de Program.cs dosyasını düzenleyin.
Öncelikle aşağıdaki Program'ın üst kısmındaki "Verbmap" bölümüne, mevcut insert komut bloğunun altına yeni bir query komut bloğu ekleyin:
[Verb("query", HelpText = "Query players with 'Top Ten' scores within a specific timespan "
+ "from sample Cloud Spanner database table.")]
class QueryOptions
{
[Value(0, HelpText = "The project ID of the project to use "
+ "when managing Cloud Spanner resources.", Required = true)]
public string projectId { get; set; }
[Value(1, HelpText = "The ID of the instance where the sample data resides.",
Required = true)]
public string instanceId { get; set; }
[Value(2, HelpText = "The ID of the database where the sample data resides.",
Required = true)]
public string databaseId { get; set; }
[Value(3, Default = 0, HelpText = "The timespan in hours that will be used to filter the "
+ "results based on a record's timestamp. The default will return the "
+ "'Top Ten' scores of all time.")]
public int timespan { get; set; }
}
Ardından, mevcut InsertScoresAsync yönteminin altına aşağıdaki Query ve QueryAsync yöntemlerini ekleyin:
public static object Query(string projectId,
string instanceId, string databaseId, int timespan)
{
var response = QueryAsync(
projectId, instanceId, databaseId, timespan);
response.Wait();
return ExitCode.Success;
}
public static async Task QueryAsync(
string projectId, string instanceId, string databaseId, int timespan)
{
string connectionString =
$"Data Source=projects/{projectId}/instances/"
+ $"{instanceId}/databases/{databaseId}";
// Create connection to Cloud Spanner.
using (var connection = new SpannerConnection(connectionString))
{
string sqlCommand;
if (timespan == 0)
{
// No timespan specified. Query Top Ten scores of all time.
sqlCommand =
@"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";
}
else
{
// Query Top Ten scores filtered by the timepan specified.
sqlCommand =
$@"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.ToString()} HOUR)
ORDER BY s.Score DESC LIMIT 10";
}
var cmd = connection.CreateSelectCommand(sqlCommand);
using (var reader = await cmd.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
Console.WriteLine("PlayerId : "
+ reader.GetFieldValue<string>("PlayerId")
+ " PlayerName : "
+ reader.GetFieldValue<string>("PlayerName")
+ " Score : "
+ string.Format("{0:n0}",
Int64.Parse(reader.GetFieldValue<string>("Score")))
+ " Timestamp : "
+ reader.GetFieldValue<string>("Timestamp").Substring(0, 10));
}
}
}
}
Ardından, query komutunun çalışır hâle gelmesi için aşağıdaki kodu Program'ınızın "Main" yöntemine ekleyin:
.Add((QueryOptions opts) => Query(
opts.projectId, opts.instanceId, opts.databaseId, opts.timespan))
query komutunu etkinleştirmek için kodu ekledikten sonra Program.cs dosyanızın nasıl görünmesi gerektiğine dair bir örnek görmek için dotnet-docs-samples/applications/leaderboard/step6 dizinindeki Program.cs dosyasını kullanabilirsiniz.
Şimdi de yeni query komutunun programın olası komutlar listesinde yer aldığını doğrulamak için programı çalıştıralım. Aşağıdaki komutu çalıştırın:
dotnet run
query komutunun artık programın varsayılan çıkışına yeni bir komut seçeneği olarak dahil edildiğini görmeniz gerekir:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): No verb selected. create Create a sample Cloud Spanner database along with sample 'Players' and 'Scores' tables in your project. insert Insert sample 'players' records or 'scores' records into the database. query Query players with 'Top Ten' scores within a specific timespan from sample Cloud Spanner database table. help Display more information on a specific command. version Display version information.
Şimdi de giriş bağımsız değişkenlerini görmek için query komutunu çalıştıralım. Şu komutu girin:
dotnet run query
Bu işlem aşağıdaki yanıtı döndürür:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): A required value not bound to option name is missing. --help Display this help screen. --version Display version information. value pos. 0 Required. The project ID of the project to use when managing Cloud Spanner resources. value pos. 1 Required. The ID of the instance where the sample data resides. value pos. 2 Required. The ID of the database where the sample data resides. value pos. 3 (Default: 0) The timespan in hours that will be used to filter the results based on a record's timestamp. The default will return the 'Top Ten' scores of all time.
Yanıtı incelediğinizde, proje kimliği, örnek kimliği ve veritabanı kimliğine ek olarak başka bir bağımsız değişkenin (value pos. 3) beklendiğini görebilirsiniz. Bu bağımsız değişken, kayıtları Scores tablosunun Timestamp sütunundaki değerlerine göre filtrelemek için kullanılacak zaman aralığını saat cinsinden belirtmemize olanak tanır. Bu bağımsız değişkenin varsayılan değeri 0'dır. Bu da kayıtların zaman damgalarına göre filtrelenmeyeceği anlamına gelir. Bu nedenle, tüm zamanların "En İyi On" oyuncusunun listesini almak için query komutunu "zaman aralığı" değeri olmadan kullanabiliriz.
query komutunu, create komutunu çalıştırırken kullandığımız bağımsız değişken değerlerini kullanarak "timespan" belirtmeden çalıştıralım. PROJECT_ID yerine bu codelab'in başında oluşturduğunuz proje kimliğini yazdığınızdan emin olun.
dotnet run query PROJECT_ID cloudspanner-leaderboard leaderboard
Aşağıdaki gibi, tüm zamanların "En İyi On" oyuncusunu içeren bir yanıt görmelisiniz:
PlayerId : 1843159180 PlayerName : Player 87 Score : 998,955 Timestamp : 2016-03-23
PlayerId : 61891198 PlayerName : Player 19 Score : 998,720 Timestamp : 2016-03-26
PlayerId : 340906298 PlayerName : Player 48 Score : 993,302 Timestamp : 2015-08-27
PlayerId : 541473117 PlayerName : Player 22 Score : 991,368 Timestamp : 2018-04-30
PlayerId : 857460496 PlayerName : Player 68 Score : 988,010 Timestamp : 2015-05-25
PlayerId : 1826646419 PlayerName : Player 91 Score : 984,022 Timestamp : 2016-11-26
PlayerId : 1002199735 PlayerName : Player 35 Score : 982,933 Timestamp : 2015-09-26
PlayerId : 2002563755 PlayerName : Player 23 Score : 979,041 Timestamp : 2016-10-25
PlayerId : 1377548191 PlayerName : Player 2 Score : 978,632 Timestamp : 2016-05-02
PlayerId : 1358098565 PlayerName : Player 65 Score : 973,257 Timestamp : 2016-10-30
Şimdi de bir yılın saat sayısına (8.760) eşit bir "zaman aralığı" belirterek yılın "En İyi On" oyuncusunu sorgulamak için gerekli bağımsız değişkenlerle query komutunu çalıştıralım. PROJECT_ID yerine bu codelab'in başında oluşturduğunuz proje kimliğini yazdığınızdan emin olun.
dotnet run query PROJECT_ID cloudspanner-leaderboard leaderboard 8760
Aşağıdaki gibi, yılın "En İyi On" oyuncusunu içeren bir yanıt görürsünüz:
PlayerId : 541473117 PlayerName : Player 22 Score : 991,368 Timestamp : 2018-04-30
PlayerId : 228469898 PlayerName : Player 82 Score : 967,177 Timestamp : 2018-01-26
PlayerId : 1131343000 PlayerName : Player 26 Score : 944,725 Timestamp : 2017-05-26
PlayerId : 396780730 PlayerName : Player 41 Score : 929,455 Timestamp : 2017-09-26
PlayerId : 61891198 PlayerName : Player 19 Score : 921,251 Timestamp : 2018-05-01
PlayerId : 634269851 PlayerName : Player 54 Score : 909,379 Timestamp : 2017-07-24
PlayerId : 821111159 PlayerName : Player 55 Score : 908,402 Timestamp : 2017-05-25
PlayerId : 228469898 PlayerName : Player 82 Score : 889,040 Timestamp : 2017-12-26
PlayerId : 1408782275 PlayerName : Player 27 Score : 874,124 Timestamp : 2017-09-24
PlayerId : 1002199735 PlayerName : Player 35 Score : 864,758 Timestamp : 2018-04-24
Şimdi de bir ayın saat sayısına (730) eşit bir "zaman aralığı" belirterek ayın "En İyi On" oyuncusunu sorgulamak için query komutunu çalıştıralım. PROJECT_ID yerine bu codelab'in başında oluşturduğunuz proje kimliğini yazdığınızdan emin olun.
dotnet run query PROJECT_ID cloudspanner-leaderboard leaderboard 730
Aşağıdaki gibi, ayın "En İyi On" oyuncusunu içeren bir yanıt görürsünüz:
PlayerId : 541473117 PlayerName : Player 22 Score : 991,368 Timestamp : 2018-04-30
PlayerId : 61891198 PlayerName : Player 19 Score : 921,251 Timestamp : 2018-05-01
PlayerId : 1002199735 PlayerName : Player 35 Score : 864,758 Timestamp : 2018-04-24
PlayerId : 1228490432 PlayerName : Player 11 Score : 682,033 Timestamp : 2018-04-26
PlayerId : 648239230 PlayerName : Player 92 Score : 653,895 Timestamp : 2018-05-02
PlayerId : 70762849 PlayerName : Player 77 Score : 598,074 Timestamp : 2018-04-22
PlayerId : 1671215342 PlayerName : Player 62 Score : 506,770 Timestamp : 2018-04-28
PlayerId : 1208850523 PlayerName : Player 21 Score : 216,008 Timestamp : 2018-04-30
PlayerId : 1587692674 PlayerName : Player 63 Score : 188,157 Timestamp : 2018-04-25
PlayerId : 992391797 PlayerName : Player 37 Score : 167,175 Timestamp : 2018-04-30
Şimdi de haftanın "En İyi On" oyuncusunu sorgulamak için query komutunu çalıştıralım. Bunu yaparken bir haftadaki saat sayısına (168) eşit bir "zaman aralığı" belirteceğiz. PROJECT_ID yerine bu codelab'in başında oluşturduğunuz proje kimliğini yazdığınızdan emin olun.
dotnet run query PROJECT_ID cloudspanner-leaderboard leaderboard 168
Aşağıdaki gibi, haftanın "En İyi On" oyuncusunu içeren bir yanıt görürsünüz:
PlayerId : 541473117 PlayerName : Player 22 Score : 991,368 Timestamp : 2018-04-30
PlayerId : 61891198 PlayerName : Player 19 Score : 921,251 Timestamp : 2018-05-01
PlayerId : 228469898 PlayerName : Player 82 Score : 853,602 Timestamp : 2018-04-28
PlayerId : 1131343000 PlayerName : Player 26 Score : 695,318 Timestamp : 2018-04-30
PlayerId : 1228490432 PlayerName : Player 11 Score : 682,033 Timestamp : 2018-04-26
PlayerId : 1408782275 PlayerName : Player 27 Score : 671,827 Timestamp : 2018-04-27
PlayerId : 648239230 PlayerName : Player 92 Score : 653,895 Timestamp : 2018-05-02
PlayerId : 816861444 PlayerName : Player 83 Score : 622,277 Timestamp : 2018-04-27
PlayerId : 162043954 PlayerName : Player 75 Score : 572,634 Timestamp : 2018-05-02
PlayerId : 1671215342 PlayerName : Player 62 Score : 506,770 Timestamp : 2018-04-28
Harika!
Artık kayıt ekledikçe Spanner, veritabanınızı istediğiniz kadar büyütebilir.
Veritabanınız ne kadar büyürse büyüsün, Spanner ve Truetime teknolojisi sayesinde oyununuzun skor tablosu doğru bir şekilde ölçeklenmeye devam edebilir.
7. Temizleme
Spanner ile oynayarak eğlendikten sonra, değerli kaynakları ve parayı korumak için oyun alanımızı temizlememiz gerekir. Neyse ki bu kolay bir adımdır. Tek yapmanız gereken geliştirici konsoluna gidip "Setup a Cloud Spanner Instance" (Cloud Spanner örneği oluşturma) adlı codelab adımında oluşturduğumuz örneği silmektir.
8. Tebrikler!
İşlediğimiz konular:
- Liderlik tablosu için Google Cloud Spanner örnekleri, veritabanları ve tablo şeması
- .NET Core C# konsol uygulaması oluşturma
- C# istemci kitaplığını kullanarak Spanner veritabanı ve tabloları oluşturma
- C# istemci kitaplığını kullanarak Spanner veritabanına veri yükleme
- Spanner kaydetme zaman damgalarını ve C# istemci kitaplığını kullanarak verilerinizdeki "En İyi On" sonuçlarını sorgulama
Sonraki Adımlar:
- Spanner CAP Teknik Belgesi'ni okuyun.
- Şema tasarımı ve sorgu ile ilgili en iyi uygulamalar hakkında bilgi edinin.
- Cloud Spanner işleme zaman damgaları hakkında daha fazla bilgi edinin.
Görüşlerinizi bizimle paylaşın
- Lütfen birkaç dakikanızı ayırarak çok kısa anketimizi doldurun.