適用於 Go 的 Amazon QLDB 驅動程式 – 快速入門教學課程 - Amazon Quantum Ledger Database (Amazon QLDB)

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

適用於 Go 的 Amazon QLDB 驅動程式 – 快速入門教學課程

重要

支援終止通知:現有客戶將可以使用 Amazon QLDB,直到 07/31/2025 的支援結束為止。如需詳細資訊,請參閱將 Amazon QLDB Ledger 遷移至 Amazon Aurora PostgreSQL

在本教學課程中,您將了解如何使用最新版本的 Amazon QLDB 驅動程式 for Go 設定簡單的應用程式。本指南包含安裝驅動程式的步驟,以及基本建立、讀取、更新和刪除 (CRUD) 操作的簡短程式碼範例。

先決條件

開始之前,請務必執行下列動作:

  1. 如果您尚未執行此操作,請完成 Go 驅動程式先決條件的 。這包括註冊 AWS、授予開發的程式設計存取權,以及安裝 Go。

  2. 建立名為 的分類帳quick-start

    若要了解如何建立分類帳,請參閱 主控台入門步驟 1:建立新的分類帳中的 Amazon QLDB 分類帳的基本操作或 。

步驟 1:安裝驅動程式

確保您的專案使用 Go 模組來安裝專案相依性。

在專案目錄中,輸入下列go get命令。

$ go get -u github.com/awslabs/amazon-qldb-driver-go/v3/qldbdriver

安裝驅動程式也會安裝其相依性,包括 適用於 Go 的 AWS SDK v2Amazon Ion 套件。

步驟 2:匯入套件

匯入下列 AWS 套件。

import ( "context" "fmt" "github.com/amzn/ion-go/ion" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/qldbSession" "github.com/awslabs/amazon-qldb-driver-go/v3/qldbdriver" )

步驟 3:初始化驅動程式

初始化連接至名為 之分類帳的驅動程式執行個體quick-start

cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { panic(err) } qldbSession := qldbsession.NewFromConfig(cfg, func(options *qldbsession.Options) { options.Region = "us-east-1" }) driver, err := qldbdriver.New( "quick-start", qldbSession, func(options *qldbdriver.DriverOptions) { options.LoggerVerbosity = qldbdriver.LogInfo }) if err != nil { panic(err) } defer driver.Shutdown(context.Background())
注意

在此程式碼範例中,將 AWS 區域 us-east-1 取代為您建立分類帳的 。

步驟 4:建立資料表和索引

下列程式碼範例示範如何執行 CREATE TABLECREATE INDEX陳述式。

_, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { _, err := txn.Execute("CREATE TABLE People") if err != nil { return nil, err } // When working with QLDB, it's recommended to create an index on fields we're filtering on. // This reduces the chance of OCC conflict exceptions with large datasets. _, err = txn.Execute("CREATE INDEX ON People (firstName)") if err != nil { return nil, err } _, err = txn.Execute("CREATE INDEX ON People (age)") if err != nil { return nil, err } return nil, nil }) if err != nil { panic(err) }

此程式碼會建立名為 的資料表People,以及該資料表上 firstNameage 欄位的索引。需要索引才能最佳化查詢效能,並協助限制樂觀並行控制 (OCC) 衝突例外狀況。

步驟 5:插入文件

下列程式碼範例示範如何執行 INSERT陳述式。QLDB 支援 PartiQL 查詢語言 (與 SQL 相容) 和 Amazon Ion 資料格式 (JSON 的超集)。

使用常值 PartiQL

下列程式碼使用字串常值 PartiQL 陳述式將文件插入People資料表。

_, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { return txn.Execute("INSERT INTO People {'firstName': 'Jane', 'lastName': 'Doe', 'age': 77}") }) if err != nil { panic(err) }

使用 Ion 資料類型

與 Go 的內建 JSON 套件類似,您可以在往返 Ion 之間合併和取消合併 Go 資料類型。

  1. 假設您有下列名為 的 Go 結構Person

    type Person struct { FirstName string `ion:"firstName"` LastName string `ion:"lastName"` Age int `ion:"age"` }
  2. 建立 Person 的執行個體。

    person := Person{"John", "Doe", 54}

    驅動程式person會為您合併 的 Ion 編碼文字表示法。

    重要

    若要讓 marshal 和 unmarshal 正常運作,必須匯出 Go 資料結構的欄位名稱 (大寫第一個字母)。

  3. person執行個體傳遞至交易的 Execute方法。

    _, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { return txn.Execute("INSERT INTO People ?", person) }) if err != nil { panic(err) }

    此範例使用問號 (?) 做為變數預留位置,將文件資訊傳遞至 陳述式。使用預留位置時,您必須傳遞 Ion 編碼的文字值。

    提示

    若要使用單一INSERT陳述式插入多個文件,您可以將類型清單的參數傳遞至陳述式,如下所示。

    // people is a list txn.Execute("INSERT INTO People ?", people)

    傳遞清單時,您不會將變數預留位置 (?) 括在雙角度括號 ( ) <<...>> 中。在手動 PartiQL 陳述式中,雙角括號表示稱為的未排序集合。

步驟 6:查詢文件

下列程式碼範例示範如何執行 SELECT陳述式。

p, err := driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { result, err := txn.Execute("SELECT firstName, lastName, age FROM People WHERE age = 54") if err != nil { return nil, err } // Assume the result is not empty hasNext := result.Next(txn) if !hasNext && result.Err() != nil { return nil, result.Err() } ionBinary := result.GetCurrentData() temp := new(Person) err = ion.Unmarshal(ionBinary, temp) if err != nil { return nil, err } return *temp, nil }) if err != nil { panic(err) } var returnedPerson Person returnedPerson = p.(Person) if returnedPerson != person { fmt.Print("Queried result does not match inserted struct") }

此範例會從People資料表查詢您的文件,假設結果集不是空的,並從結果傳回您的文件。

步驟 7:更新文件

下列程式碼範例示範如何執行 UPDATE陳述式。

person.Age += 10 _, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { return txn.Execute("UPDATE People SET age = ? WHERE firstName = ?", person.Age, person.FirstName) }) if err != nil { panic(err) }

步驟 8:查詢更新的文件

下列程式碼範例會查詢 People 資料表,firstName並傳回結果集中的所有文件。

p, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { result, err := txn.Execute("SELECT firstName, lastName, age FROM People WHERE firstName = ?", person.FirstName) if err != nil { return nil, err } var people []Person for result.Next(txn) { ionBinary := result.GetCurrentData() temp := new(Person) err = ion.Unmarshal(ionBinary, temp) if err != nil { return nil, err } people = append(people, *temp) } if result.Err() != nil { return nil, result.Err() } return people, nil }) if err != nil { panic(err) } var people []Person people = p.([]Person) updatedPerson := Person{"John", "Doe", 64} if people[0] != updatedPerson { fmt.Print("Queried result does not match updated struct") }

步驟 9:捨棄資料表

下列程式碼範例示範如何執行 DROP TABLE陳述式。

_, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { return txn.Execute("DROP TABLE People") }) if err != nil { panic(err) }

執行完整的應用程式

下列程式碼範例是應用程式的完整版本。您也可以從頭到尾複製並執行此程式碼範例,而不是個別執行上述步驟。此應用程式會在名為 的分類帳上示範一些基本 CRUD 操作quick-start

注意

在您執行此程式碼之前,請確定您尚未在分類帳People中擁有名為 quick-start 的作用中資料表。

package main import ( "context" "fmt" "github.com/amzn/ion-go/ion" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/qldbsession" "github.com/awslabs/amazon-qldb-driver-go/v2/qldbdriver" ) func main() { awsSession := session.Must(session.NewSession(aws.NewConfig().WithRegion("us-east-1"))) qldbSession := qldbsession.New(awsSession) driver, err := qldbdriver.New( "quick-start", qldbSession, func(options *qldbdriver.DriverOptions) { options.LoggerVerbosity = qldbdriver.LogInfo }) if err != nil { panic(err) } defer driver.Shutdown(context.Background()) _, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { _, err := txn.Execute("CREATE TABLE People") if err != nil { return nil, err } // When working with QLDB, it's recommended to create an index on fields we're filtering on. // This reduces the chance of OCC conflict exceptions with large datasets. _, err = txn.Execute("CREATE INDEX ON People (firstName)") if err != nil { return nil, err } _, err = txn.Execute("CREATE INDEX ON People (age)") if err != nil { return nil, err } return nil, nil }) if err != nil { panic(err) } _, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { return txn.Execute("INSERT INTO People {'firstName': 'Jane', 'lastName': 'Doe', 'age': 77}") }) if err != nil { panic(err) } type Person struct { FirstName string `ion:"firstName"` LastName string `ion:"lastName"` Age int `ion:"age"` } person := Person{"John", "Doe", 54} _, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { return txn.Execute("INSERT INTO People ?", person) }) if err != nil { panic(err) } p, err := driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { result, err := txn.Execute("SELECT firstName, lastName, age FROM People WHERE age = 54") if err != nil { return nil, err } // Assume the result is not empty hasNext := result.Next(txn) if !hasNext && result.Err() != nil { return nil, result.Err() } ionBinary := result.GetCurrentData() temp := new(Person) err = ion.Unmarshal(ionBinary, temp) if err != nil { return nil, err } return *temp, nil }) if err != nil { panic(err) } var returnedPerson Person returnedPerson = p.(Person) if returnedPerson != person { fmt.Print("Queried result does not match inserted struct") } person.Age += 10 _, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { return txn.Execute("UPDATE People SET age = ? WHERE firstName = ?", person.Age, person.FirstName) }) if err != nil { panic(err) } p, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { result, err := txn.Execute("SELECT firstName, lastName, age FROM People WHERE firstName = ?", person.FirstName) if err != nil { return nil, err } var people []Person for result.Next(txn) { ionBinary := result.GetCurrentData() temp := new(Person) err = ion.Unmarshal(ionBinary, temp) if err != nil { return nil, err } people = append(people, *temp) } if result.Err() != nil { return nil, result.Err() } return people, nil }) if err != nil { panic(err) } var people []Person people = p.([]Person) updatedPerson := Person{"John", "Doe", 64} if people[0] != updatedPerson { fmt.Print("Queried result does not match updated struct") } _, err = driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) { return txn.Execute("DROP TABLE People") }) if err != nil { panic(err) } }