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 در اختیار دارید.
در مرحله بعدی از کتابخانه سرویس گیرنده Go برای ایجاد یک پایگاه داده و طرحواره در نمونه جدید خود استفاده می کنیم.
4. یک پایگاه داده و طرحواره ایجاد کنید
در این مرحله میخواهیم پایگاه داده و طرحواره خود را بسازیم.
بیایید از کتابخانه سرویس گیرنده Go برای ایجاد دو جدول استفاده کنیم. یک جدول بازیکنان برای اطلاعات بازیکن و یک جدول امتیازات برای ذخیره امتیازات بازیکنان. برای انجام این کار، مراحل ایجاد یک برنامه کنسول Go در Cloud Shell را طی می کنیم.
ابتدا با تایپ دستور زیر در Cloud Shell، کد نمونه این کد لبه را از Github کلون کنید:
export GO111MODULE=auto
go get -u github.com/GoogleCloudPlatform/golang-samples/spanner/...
سپس دایرکتوری را به دایرکتوری "Leaderboard" تغییر دهید که در آن برنامه خود را ایجاد خواهید کرد.
cd gopath/src/github.com/GoogleCloudPlatform/golang-samples/spanner/spanner_leaderboard
تمام کدهای مورد نیاز برای این کد لبه در فهرست راهنمای golang-samples/spanner/spanner_leaderboard/
موجود به عنوان یک برنامه Go قابل اجرا با نام leaderboard
قرار دارد تا در حین پیشروی شما از طریق Codelab به عنوان مرجع عمل کند. ما یک دایرکتوری جدید ایجاد می کنیم و یک کپی از برنامه Leaderboard در مراحل ایجاد می کنیم.
یک دایرکتوری جدید با نام "codelab" برای برنامه ایجاد کنید و دایرکتوری را با دستور زیر به آن تغییر دهید:
mkdir codelab && cd $_
حالا بیایید یک برنامه اصلی Go به نام "Leaderboard" ایجاد کنیم که از کتابخانه کلاینت Spanner برای ایجاد تابلوی امتیازات متشکل از دو جدول استفاده می کند. بازیکنان و امتیازات می توانید این کار را درست در ویرایشگر پوسته ابری انجام دهید:
ویرایشگر پوسته ابری را با کلیک بر روی نماد «ویرایشگر باز» که در زیر مشخص شده است، باز کنید:
فایلی با نام "leaderboard.go" در پوشه ~/gopath/src/github.com/GoogleCloudPlatform/golang-samples/spanner/codelab ایجاد کنید.
- ابتدا مطمئن شوید که پوشه "codelab" را در لیست پوشه های Cloud Shell Editor انتخاب کرده اید.
- سپس «فایل جدید» را در منوی «فایل» ویرایشگر پوسته ابری انتخاب کنید.
- "leaderboard.go" را به عنوان نام فایل جدید وارد کنید.
این فایل اصلی برنامه است که حاوی کد برنامه ما و ارجاعاتی است که وابستگی ها را شامل می شود.
برای ایجاد پایگاه داده leaderboard
و جداول Players
و Scores
، کد Go زیر را در فایل leaderboard.go
کپی کنید (Ctrl + P) و (Ctrl + V) پیست کنید:
package main
import (
"context"
"flag"
"fmt"
"io"
"log"
"os"
"regexp"
"time"
"cloud.google.com/go/spanner"
database "cloud.google.com/go/spanner/admin/database/apiv1"
adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
)
type adminCommand func(ctx context.Context, w io.Writer, adminClient *database.DatabaseAdminClient, database string) error
func createDatabase(ctx context.Context, w io.Writer, adminClient *database.DatabaseAdminClient, db string) error {
matches := regexp.MustCompile("^(.*)/databases/(.*)$").FindStringSubmatch(db)
if matches == nil || len(matches) != 3 {
return fmt.Errorf("Invalid database id %s", db)
}
op, err := adminClient.CreateDatabase(ctx, &adminpb.CreateDatabaseRequest{
Parent: matches[1],
CreateStatement: "CREATE DATABASE `" + matches[2] + "`",
ExtraStatements: []string{
`CREATE TABLE Players(
PlayerId INT64 NOT NULL,
PlayerName STRING(2048) NOT NULL
) PRIMARY KEY(PlayerId)`,
`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`,
},
})
if err != nil {
return err
}
if _, err := op.Wait(ctx); err != nil {
return err
}
fmt.Fprintf(w, "Created database [%s]\n", db)
return nil
}
func createClients(ctx context.Context, db string) (*database.DatabaseAdminClient, *spanner.Client) {
adminClient, err := database.NewDatabaseAdminClient(ctx)
if err != nil {
log.Fatal(err)
}
dataClient, err := spanner.NewClient(ctx, db)
if err != nil {
log.Fatal(err)
}
return adminClient, dataClient
}
func run(ctx context.Context, adminClient *database.DatabaseAdminClient, dataClient *spanner.Client, w io.Writer,
cmd string, db string, timespan int) error {
// createdatabase command
if cmd == "createdatabase" {
err := createDatabase(ctx, w, adminClient, db)
if err != nil {
fmt.Fprintf(w, "%s failed with %v", cmd, err)
}
return err
}
return nil
}
func main() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: leaderboard <command> <database_name> [command_option]
Command can be one of: createdatabase
Examples:
leaderboard createdatabase projects/my-project/instances/my-instance/databases/example-db
- Create a sample Cloud Spanner database along with sample tables in your project.
`)
}
flag.Parse()
flagCount := len(flag.Args())
if flagCount != 2 {
flag.Usage()
os.Exit(2)
}
cmd, db := flag.Arg(0), flag.Arg(1)
// Set timespan to zero, as it's not currently being used
var timespan int = 0
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
adminClient, dataClient := createClients(ctx, db)
if err := run(ctx, adminClient, dataClient, os.Stdout, cmd, db, timespan); err != nil {
os.Exit(1)
}
}
با انتخاب «ذخیره» در منوی «فایل» ویرایشگر Cloud Shell، تغییراتی را که در فایل leaderboard.go
ایجاد کردهاید، ذخیره کنید.
میتوانید از فایل leaderboard.go
در فهرست راهنمای golang-samples/spanner/spanner_leaderboard
استفاده کنید تا نمونهای از نحوه نگاه فایل leaderboard.go
شما پس از افزودن کد برای فعال کردن دستور createdatabase
را ببینید.
برای ساخت برنامه خود در Cloud Shell، «go build» را از پوشه codelab
که فایل leaderboard.go
شما در آن قرار دارد اجرا کنید:
go build leaderboard.go
هنگامی که برنامه شما با موفقیت ساخته شد، برنامه به دست آمده را با وارد کردن دستور زیر در Cloud Shell اجرا کنید:
./leaderboard
شما باید خروجی را مانند زیر ببینید:
Usage: leaderboard <command> <database_name> [command_option] Command can be one of: createdatabase Examples: leaderboard createdatabase projects/my-project/instances/my-instance/databases/example-db - Create a sample Cloud Spanner database along with sample tables in your project.
از این پاسخ می بینیم که این برنامه Leaderboard
است که در حال حاضر یک دستور ممکن دارد: createdatabase
. میتوانیم ببینیم که آرگومان مورد انتظار دستور createdatabase
رشتهای است که شامل شناسه نمونه و شناسه پایگاه داده خاص است.
حالا دستور زیر را اجرا کنید. مطمئن شوید که my-project
با شناسه پروژه ای که در ابتدای این کد لبه ایجاد کرده اید جایگزین کرده اید.
./leaderboard createdatabase projects/my-project/instances/cloudspanner-leaderboard/databases/leaderboard
پس از چند ثانیه باید پاسخی مانند زیر را مشاهده کنید:
Created database [projects/my-project/instances/cloudspanner-leaderboard/databases/leaderboard]
در بخش نمای کلی پایگاههای داده Cloud Spanner در Cloud Console، باید پایگاه داده و جداول جدید خود را در منوی سمت چپ مشاهده کنید.
در مرحله بعدی برنامه خود را برای بارگیری برخی از داده ها در پایگاه داده جدید شما به روز می کنیم.
5. بارگذاری داده ها
ما اکنون یک پایگاه داده به نام leaderboard
داریم که شامل دو جدول است. Players
و Scores
اکنون بیایید از کتابخانه مشتری Go استفاده کنیم تا جدول Players
خود را با بازیکنان و جدول Scores
خود را با امتیازهای تصادفی برای هر بازیکن پر کنیم.
اگر قبلاً باز نشده است، ویرایشگر پوسته ابری را با کلیک بر روی نماد برجسته شده در زیر باز کنید:
در مرحله بعد، فایل leaderboard.go
را در ویرایشگر پوسته ابری ویرایش کنید تا دستور insertplayers
اضافه کنید که می تواند برای وارد کردن 100 بازیکن در جدول Players
استفاده شود. ما همچنین یک دستور insertscores
اضافه می کنیم که می تواند برای درج 4 امتیاز تصادفی در جدول Scores
برای هر بازیکن در جدول Players
استفاده شود.
ابتدا بخش imports
را در بالای فایل leaderboard.go
بهروزرسانی کنید، و جایگزین آنچه در حال حاضر وجود دارد را جایگزین کنید، به طوری که پس از اتمام کار به شکل زیر باشد:
import (
"context"
"flag"
"fmt"
"io"
"log"
"math/rand"
"os"
"regexp"
"time"
"cloud.google.com/go/spanner"
database "cloud.google.com/go/spanner/admin/database/apiv1"
"google.golang.org/api/iterator"
adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
)
سپس یک نوع دستور جدید به همراه لیستی از دستورات را در بالای فایل، درست زیر خطی که با "type adminCommand ..." شروع می شود، اضافه کنید، به طوری که پس از اتمام کار، مانند زیر باشد:
type adminCommand func(ctx context.Context, w io.Writer, adminClient *database.DatabaseAdminClient, database string) error
type command func(ctx context.Context, w io.Writer, client *spanner.Client) error
var (
commands = map[string]command{
"insertplayers": insertPlayers,
"insertscores": insertScores,
}
)
سپس insertPlayers زیر را اضافه کنید و توابع insertScores را زیر تابع createdatabase()
موجود اضافه کنید:
func insertPlayers(ctx context.Context, w io.Writer, client *spanner.Client) error {
// Get number of players to use as an incrementing value for each PlayerName to be inserted
stmt := spanner.Statement{
SQL: `SELECT Count(PlayerId) as PlayerCount FROM Players`,
}
iter := client.Single().Query(ctx, stmt)
defer iter.Stop()
row, err := iter.Next()
if err != nil {
return err
}
var numberOfPlayers int64 = 0
if err := row.Columns(&numberOfPlayers); err != nil {
return err
}
// Initialize values for random PlayerId
rand.Seed(time.Now().UnixNano())
min := 1000000000
max := 9000000000
// Insert 100 player records into the Players table
_, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
stmts := []spanner.Statement{}
for i := 1; i <= 100; i++ {
numberOfPlayers++
playerID := rand.Intn(max-min) + min
playerName := fmt.Sprintf("Player %d", numberOfPlayers)
stmts = append(stmts, spanner.Statement{
SQL: `INSERT INTO Players
(PlayerId, PlayerName)
VALUES (@playerID, @playerName)`,
Params: map[string]interface{}{
"playerID": playerID,
"playerName": playerName,
},
})
}
_, err := txn.BatchUpdate(ctx, stmts)
if err != nil {
return err
}
return nil
})
fmt.Fprintf(w, "Inserted players \n")
return nil
}
func insertScores(ctx context.Context, w io.Writer, client *spanner.Client) error {
playerRecordsFound := false
// Create slice for insert statements
stmts := []spanner.Statement{}
// Select all player records
stmt := spanner.Statement{SQL: `SELECT PlayerId FROM Players`}
iter := client.Single().Query(ctx, stmt)
defer iter.Stop()
// Insert 4 score records into the Scores table for each player in the Players table
for {
row, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
return err
}
playerRecordsFound = true
var playerID int64
if err := row.ColumnByName("PlayerId", &playerID); err != nil {
return err
}
// Initialize values for random score and date
rand.Seed(time.Now().UnixNano())
min := 1000
max := 1000000
for i := 0; i < 4; i++ {
// Generate random score between 1,000 and 1,000,000
score := rand.Intn(max-min) + min
// Generate random day within the past two years
now := time.Now()
endDate := now.Unix()
past := now.AddDate(0, -24, 0)
startDate := past.Unix()
randomDateInSeconds := rand.Int63n(endDate-startDate) + startDate
randomDate := time.Unix(randomDateInSeconds, 0)
// Add insert statement to stmts slice
stmts = append(stmts, spanner.Statement{
SQL: `INSERT INTO Scores
(PlayerId, Score, Timestamp)
VALUES (@playerID, @score, @timestamp)`,
Params: map[string]interface{}{
"playerID": playerID,
"score": score,
"timestamp": randomDate,
},
})
}
}
if !playerRecordsFound {
fmt.Fprintln(w, "No player records currently exist. First insert players then insert scores.")
} else {
_, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
// Commit insert statements for all scores to be inserted as a single transaction
_, err := txn.BatchUpdate(ctx, stmts)
return err
})
if err != nil {
return err
}
fmt.Fprintln(w, "Inserted scores")
}
return nil
}
سپس، برای کاربردی کردن دستور insert
، کد زیر را به تابع "run" برنامه خود در زیر عبارت createdatabase
و جایگزین عبارت return nil
اضافه کنید:
// insert and query commands
cmdFn := commands[cmd]
if cmdFn == nil {
flag.Usage()
os.Exit(2)
}
err := cmdFn(ctx, w, dataClient)
if err != nil {
fmt.Fprintf(w, "%s failed with %v", cmd, err)
}
return err
پس از اتمام کار، تابع run
باید به شکل زیر باشد:
func run(ctx context.Context, adminClient *database.DatabaseAdminClient, dataClient *spanner.Client, w io.Writer,
cmd string, db string, timespan int) error {
// createdatabase command
if cmd == "createdatabase" {
err := createDatabase(ctx, w, adminClient, db)
if err != nil {
fmt.Fprintf(w, "%s failed with %v", cmd, err)
}
return err
}
// insert and query commands
cmdFn := commands[cmd]
if cmdFn == nil {
flag.Usage()
os.Exit(2)
}
err := cmdFn(ctx, w, dataClient)
if err != nil {
fmt.Fprintf(w, "%s failed with %v", cmd, err)
}
return err
}
آخرین مرحله برای تکمیل افزودن قابلیت "insert" به برنامه شما، افزودن متن راهنما برای دستورات "insertplayers" و "insertscores" به تابع flag.Usage()
است. متن راهنما زیر را به flag.Usage()
اضافه کنید تا متن راهنما را برای دستورات درج اضافه کنید:
دو دستور را به لیست دستورات ممکن اضافه کنید:
Command can be one of: createdatabase, insertplayers, insertscores
و این متن کمکی اضافی را در زیر متن راهنما برای دستور createdatabase
اضافه کنید.
leaderboard insertplayers projects/my-project/instances/my-instance/databases/example-db
- Insert 100 sample Player records into the database.
leaderboard insertscores projects/my-project/instances/my-instance/databases/example-db
- Insert sample score data into Scores sample Cloud Spanner database table.
با انتخاب «ذخیره» در منوی «فایل» ویرایشگر Cloud Shell، تغییراتی را که در فایل leaderboard.go
ایجاد کردهاید، ذخیره کنید.
میتوانید از فایل leaderboard.go
در فهرست راهنمای golang-samples/spanner/spanner_leaderboard
استفاده کنید تا نمونهای از نحوه نگاه فایل leaderboard.go
شما پس از افزودن کد برای فعال کردن دستورات insertplayers
و insertscores
را ببینید.
حالا بیایید برنامه را بسازیم و اجرا کنیم تا تأیید کنیم که دستورات insertplayers
و insertscores
جدید در لیست دستورات ممکن برنامه گنجانده شده است. دستور زیر را برای ساخت اپلیکیشن اجرا کنید:
go build leaderboard.go
با وارد کردن دستور زیر برنامه به دست آمده را در پوسته ابری اجرا کنید:
./leaderboard
اکنون باید دستورات insertplayers
و insertscores
در خروجی پیش فرض برنامه مشاهده کنید:
Usage: leaderboard <command> <database_name> [command_option] Command can be one of: createdatabase, insertplayers, insertscores Examples: leaderboard createdatabase projects/my-project/instances/my-instance/databases/example-db - Create a sample Cloud Spanner database along with sample tables in your project. leaderboard insertplayers projects/my-project/instances/my-instance/databases/example-db - Insert 100 sample Player records into the database. leaderboard insertscores projects/my-project/instances/my-instance/databases/example-db - Insert sample score data into Scores sample Cloud Spanner database table.
حالا بیایید دستور insertplayers
را با همان مقادیر آرگومان که هنگام فراخوانی دستور createdatabase
استفاده کردیم، اجرا کنیم. مطمئن شوید که my-project
با شناسه پروژه ای که در ابتدای این کد لبه ایجاد کرده اید جایگزین کرده اید.
./leaderboard insertplayers projects/my-project/instances/cloudspanner-leaderboard/databases/leaderboard
پس از چند ثانیه باید پاسخی مانند زیر را مشاهده کنید:
Inserted players
اکنون بیایید از کتابخانه سرویس گیرنده Go استفاده کنیم تا جدول 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 در یک ردیف جدول مشخص شود.
همچنین میتوانید مقادیر مهر زمانی خود را در ستون «مهر زمانی تعهد» درج کنید، البته تا زمانی که یک مهر زمانی با مقداری در گذشته وارد کنید، این همان کاری است که ما برای هدف این آزمایشگاه انجام خواهیم داد.
حالا بیایید دستور insertscores
را با همان مقادیر آرگومان که هنگام فراخوانی دستور insertplayers
استفاده کردیم، اجرا کنیم. مطمئن شوید که my-project
با شناسه پروژه ای که در ابتدای این کد لبه ایجاد کرده اید جایگزین کرده اید.
./leaderboard insertscores projects/my-project/instances/cloudspanner-leaderboard/databases/leaderboard
پس از چند ثانیه باید پاسخی مانند زیر را مشاهده کنید:
Inserted scores
اجرای تابع insertScores
از قطعه کد زیر برای درج مهر زمانی تولید شده به طور تصادفی با تاریخ-زمان در گذشته استفاده می کند:
now := time.Now()
endDate := now.Unix()
past := now.AddDate(0, -24, 0)
startDate := past.Unix()
randomDateInSeconds := rand.Int63n(endDate-startDate) + startDate
randomDate := time.Unix(randomDateInSeconds, 0)
stmts = append(stmts, spanner.Statement{
SQL: `INSERT INTO Scores
(PlayerId, Score, Timestamp)
VALUES (@playerID, @score, @timestamp)`,
Params: map[string]interface{}{
"playerID": playerID,
"score": score,
"timestamp": randomDate,
},
})
برای پر کردن خودکار ستون Timestamp
با مهر زمانی دقیقاً زمانی که تراکنش «Insert» انجام میشود، میتوانید به جای آن، spanner.CommitTimestamp
ثابت Go را مانند قطعه کد زیر وارد کنید.
...
stmts = append(stmts, spanner.Statement{
SQL: `INSERT INTO Scores
(PlayerId, Score, Timestamp)
VALUES (@playerID, @score, @timestamp)`,
Params: map[string]interface{}{
"playerID": playerID,
"score": score,
"timestamp": spanner.CommitTimestamp,
},
})
اکنون که بارگیری داده ها را کامل کرده ایم، بیایید مقادیری را که به تازگی در جداول جدید خود در بخش Cloud Spanner در Cloud Console نوشته ایم، تأیید کنیم. ابتدا پایگاه داده leaderboard
را انتخاب کنید و سپس جدول Players
را انتخاب کنید. روی تب Data
کلیک کنید. باید ببینید که دادههایی در ستونهای PlayerId
و PlayerName
جدول دارید.
سپس اجازه دهید با کلیک بر روی جدول Scores
و انتخاب زبانه Data
، بررسی کنیم که جدول امتیازات نیز دارای داده است. باید ببینید که دادههایی در ستونهای PlayerId
، Timestamp
و Score
جدول دارید.
آفرین! بیایید برنامه خود را به روز کنیم تا برخی از پرس و جوها را اجرا کنیم تا بتوانیم از آنها برای ایجاد تابلوی امتیازات بازی استفاده کنیم.
6. کوئری های تابلوی امتیازات را اجرا کنید
اکنون که پایگاه داده خود را راه اندازی کرده ایم و اطلاعات را در جداول خود بارگذاری کرده ایم، بیایید با استفاده از این داده ها یک تابلوی امتیازات ایجاد کنیم. برای این کار باید به چهار سوال زیر پاسخ دهیم:
- کدام بازیکنان "ده" برتر تمام دوران هستند؟
- کدام بازیکنان "ده" برتر سال هستند؟
- کدام بازیکنان "ده" برتر ماه هستند؟
- کدام بازیکنان "ده" برتر هفته هستند؟
بیایید برنامه خود را برای اجرای پرس و جوهای SQL که به این سؤالات پاسخ می دهند، به روز کنیم.
ما یک دستور query
و یک دستور queryWithTimespan
را اضافه می کنیم که راهی برای اجرای پرس و جوها برای پاسخ به سوالاتی که اطلاعات مورد نیاز برای تابلوی امتیازات ما را تولید می کند، ارائه می دهد.
فایل leaderboard.go
را در Cloud Shell Editor ویرایش کنید تا برنامه را برای اضافه کردن یک دستور query
و یک دستور queryWithTimespan
به روز کنید. ما همچنین یک تابع کمکی formatWithCommas
اضافه می کنیم تا نمرات خود را با کاما قالب بندی کنیم.
ابتدا بخش imports
را در بالای فایل leaderboard.go
بهروزرسانی کنید، و جایگزین آنچه در حال حاضر وجود دارد را جایگزین کنید، به طوری که پس از اتمام کار به شکل زیر باشد:
import (
"bytes"
"context"
"flag"
"fmt"
"io"
"log"
"math/rand"
"os"
"regexp"
"strconv"
"time"
"cloud.google.com/go/spanner"
database "cloud.google.com/go/spanner/admin/database/apiv1"
"google.golang.org/api/iterator"
adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
)
سپس دو تابع زیر و تابع کمکی را در زیر متد insertScores
موجود اضافه کنید:
func query(ctx context.Context, w io.Writer, client *spanner.Client) error {
stmt := spanner.Statement{
SQL: `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`}
iter := client.Single().Query(ctx, stmt)
defer iter.Stop()
for {
row, err := iter.Next()
if err == iterator.Done {
return nil
}
if err != nil {
return err
}
var playerID, score int64
var playerName string
var timestamp time.Time
if err := row.Columns(&playerID, &playerName, &score, ×tamp); err != nil {
return err
}
fmt.Fprintf(w, "PlayerId: %d PlayerName: %s Score: %s Timestamp: %s\n",
playerID, playerName, formatWithCommas(score), timestamp.String()[0:10])
}
}
func queryWithTimespan(ctx context.Context, w io.Writer, client *spanner.Client, timespan int) error {
stmt := spanner.Statement{
SQL: `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`,
Params: map[string]interface{}{"Timespan": timespan},
}
iter := client.Single().Query(ctx, stmt)
defer iter.Stop()
for {
row, err := iter.Next()
if err == iterator.Done {
return nil
}
if err != nil {
return err
}
var playerID, score int64
var playerName string
var timestamp time.Time
if err := row.Columns(&playerID, &playerName, &score, ×tamp); err != nil {
return err
}
fmt.Fprintf(w, "PlayerId: %d PlayerName: %s Score: %s Timestamp: %s\n",
playerID, playerName, formatWithCommas(score), timestamp.String()[0:10])
}
}
func formatWithCommas(n int64) string {
numberAsString := strconv.FormatInt(n, 10)
numberLength := len(numberAsString)
if numberLength < 4 {
return numberAsString
}
var buffer bytes.Buffer
comma := []rune(",")
bufferPosition := numberLength % 3
if (bufferPosition) > 0 {
bufferPosition = 3 - bufferPosition
}
for i := 0; i < numberLength; i++ {
if bufferPosition == 3 {
buffer.WriteRune(comma[0])
bufferPosition = 0
}
bufferPosition++
buffer.WriteByte(numberAsString[i])
}
return buffer.String()
}
سپس در بالای فایل leaderboard.go
"query" را به عنوان یکی از گزینه های فرمان در متغیر commands
، درست زیر " insertscores": insertScores
به طوری که متغیر commands
به شکل زیر باشد:
var (
commands = map[string]command{
"insertplayers": insertPlayers,
"insertscores": insertScores,
"query": query,
}
)
سپس «queryWithTimespan» را بهعنوان یک گزینه فرمان در تابع run
، زیر بخش فرمان «createdatabase» و بالای بخش مدیریت دستورات «insert and query» اضافه کنید:
// querywithtimespan command
if cmd == "querywithtimespan" {
err := queryWithTimespan(ctx, w, dataClient, timespan)
if err != nil {
fmt.Fprintf(w, "%s failed with %v", cmd, err)
}
return err
}
پس از اتمام کار، تابع run
باید به شکل زیر باشد:
func run(ctx context.Context, adminClient *database.DatabaseAdminClient, dataClient *spanner.Client, w io.Writer,
cmd string, db string, timespan int) error {
// createdatabase command
if cmd == "createdatabase" {
err := createDatabase(ctx, w, adminClient, db)
if err != nil {
fmt.Fprintf(w, "%s failed with %v", cmd, err)
}
return err
}
// querywithtimespan command
if cmd == "querywithtimespan" {
if timespan == 0 {
flag.Usage()
os.Exit(2)
}
err := queryWithTimespan(ctx, w, dataClient, timespan)
if err != nil {
fmt.Fprintf(w, "%s failed with %v", cmd, err)
}
return err
}
// insert and query commands
cmdFn := commands[cmd]
if cmdFn == nil {
flag.Usage()
os.Exit(2)
}
err := cmdFn(ctx, w, dataClient)
if err != nil {
fmt.Fprintf(w, "%s failed with %v", cmd, err)
}
return err
}
سپس، برای کاربردی کردن دستور queryWithTimespan
، بلوک کد flag.Parse() را در متد "main" برنامه خود بهروزرسانی کنید تا به شکل زیر باشد:
flag.Parse()
flagCount := len(flag.Args())
if flagCount < 2 || flagCount > 3 {
flag.Usage()
os.Exit(2)
}
cmd, db := flag.Arg(0), flag.Arg(1)
// If query timespan flag is specified, parse to int
var timespan int = 0
if flagCount == 3 {
parsedTimespan, err := strconv.Atoi(flag.Arg(2))
if err != nil {
fmt.Println(err)
os.Exit(2)
}
timespan = parsedTimespan
}
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
adminClient, dataClient := createClients(ctx, db)
if err := run(ctx, adminClient, dataClient, os.Stdout, cmd, db, timespan); err != nil {
os.Exit(1)
}
آخرین مرحله برای تکمیل افزودن قابلیت "query" به برنامه شما، افزودن متن راهنما برای دستورات "query" و "querywithtimespan" به تابع flag.Usage()
است. خطوط کد زیر را به تابع flag.Usage()
اضافه کنید تا متن راهنما برای دستورات query اضافه شود:
دو دستور query را به لیست دستورات ممکن اضافه کنید:
Command can be one of: createdatabase, insertplayers, insertscores, query, querywithtimespan
و این متن کمکی اضافی را در زیر متن راهنما برای دستور insertscores
اضافه کنید.
leaderboard query projects/my-project/instances/my-instance/databases/example-db
- Query players with top ten scores of all time.
leaderboard querywithtimespan projects/my-project/instances/my-instance/databases/example-db 168
- Query players with top ten scores within a timespan specified in hours.
با انتخاب «ذخیره» در منوی «فایل» ویرایشگر Cloud Shell، تغییراتی را که در فایل leaderboard.go
ایجاد کردهاید، ذخیره کنید.
میتوانید از فایل leaderboard.go
در فهرست راهنمای golang-samples/spanner/spanner_leaderboard
استفاده کنید تا نمونهای از نحوه نگاه فایل leaderboard.go
شما پس از افزودن کد برای فعال کردن دستورات query
و querywithtimespan
را ببینید.
حالا بیایید برنامه را بسازیم و اجرا کنیم تا تأیید کنیم که دستورات query
و querywithtimespan
جدید در لیست دستورات ممکن برنامه گنجانده شده است.
برای ساخت اپلیکیشن دستور زیر را در Cloud Shell اجرا کنید:
go build leaderboard.go
با وارد کردن دستور زیر برنامه به دست آمده را در پوسته ابری اجرا کنید:
./leaderboard
اکنون باید دستورات query
و querywithtimespan
را به عنوان یک گزینه دستور جدید در خروجی پیشفرض برنامه مشاهده کنید:
Usage: leaderboard <command> <database_name> [command_option] Command can be one of: createdatabase, insertplayers, insertscores, query, querywithtimespan Examples: leaderboard createdatabase projects/my-project/instances/my-instance/databases/example-db - Create a sample Cloud Spanner database along with sample tables in your project. leaderboard insertplayers projects/my-project/instances/my-instance/databases/example-db - Insert 100 sample Player records into the database. leaderboard insertscores projects/my-project/instances/my-instance/databases/example-db - Insert sample score data into Scores sample Cloud Spanner database table. leaderboard query projects/my-project/instances/my-instance/databases/example-db - Query players with top ten scores of all time. leaderboard querywithtimespan projects/my-project/instances/my-instance/databases/example-db 168 - Query players with top ten scores within a timespan specified in hours.
از پاسخ میبینید که میتوانیم از دستور query
برای دریافت لیستی از "ده بازیکن برتر" خود در تمام دوران استفاده کنیم. همچنین میتوانیم ببینیم که دستور querywithtimespan
به ما اجازه میدهد یک بازه زمانی را بر حسب ساعت تعیین کنیم تا از آن برای فیلتر کردن رکوردها بر اساس مقدار آنها در ستون Timestamp
جدول Scores
استفاده کنیم.
بیایید دستور query
را با استفاده از همان مقادیر آرگومان که هنگام اجرای دستور create
استفاده می کردیم، اجرا کنیم. مطمئن شوید که my-project
با شناسه پروژه ای که در ابتدای این کد لبه ایجاد کرده اید جایگزین کرده اید.
./leaderboard query projects/my-project/instances/cloudspanner-leaderboard/databases/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
حالا بیایید دستور querywithtimespan
را با آرگومان های لازم برای پرس و جو از "ده بازیکن برتر" سال اجرا کنیم، با تعیین "زمان زمانی" برابر با تعداد ساعت های یک سال که 8760 است. مطمئن شوید که my-project
را جایگزین پروژه کرده اید. شناسه ای که در ابتدای این کد لبه ایجاد کردید.
./leaderboard querywithtimespan projects/my-project/instances/cloudspanner-leaderboard/databases/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
حالا بیایید دستور querywithtimespan
را اجرا کنیم تا با تعیین یک "زمان زمانی" برابر با تعداد ساعت های یک ماه که 730 ساعت است، از "ده بازیکن برتر" ماه پرس و جو کنیم. مطمئن شوید که my-project
را با ID پروژه ای که در آن ایجاد کرده اید جایگزین کنید ابتدای این کد لبه.
./leaderboard querywithtimespan projects/my-project/instances/cloudspanner-leaderboard/databases/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
حالا بیایید دستور querywithtimespan
را اجرا کنیم تا با تعیین یک "زمان زمانی" برابر با تعداد ساعت های هفته که 168 است my-project
"ده بازیکن برتر" هفته پرس و جو کنیم . ابتدای این کد لبه.
./leaderboard querywithtimespan projects/my-project/instances/cloudspanner-leaderboard/databases/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، پایگاههای داده و جدول جدول برای تابلوی امتیازات
- نحوه ایجاد اپلیکیشن کنسول Go
- نحوه ایجاد یک پایگاه داده و جداول Spanner با استفاده از کتابخانه سرویس گیرنده Go
- نحوه بارگذاری داده ها در پایگاه داده Spanner با استفاده از کتابخانه سرویس گیرنده Go
- نحوه پرس و جو کردن نتایج "Top Ten" از داده های خود با استفاده از مهر زمانی Spanner commit و کتابخانه سرویس گیرنده Go
مراحل بعدی:
- کاغذ سفید Spanner CAP را بخوانید
- درباره بهترین شیوه های طراحی طرحواره و پرس و جو بیاموزید
- درباره مهرهای زمانی commit Cloud Spanner بیشتر بیاموزید
نظرات خود را با ما در میان بگذارید
- لطفا یک لحظه برای تکمیل نظرسنجی بسیار کوتاه ما وقت بگذارید