

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

# 適用於 Go 的 Amazon QLDB 驅動程式 – 快速入門教學課程
<a name="driver-quickstart-golang"></a>

**重要**  
支援終止通知：現有客戶將可以使用 Amazon QLDB，直到 07/31/2025 的支援結束為止。如需詳細資訊，請參閱[將 Amazon QLDB Ledger 遷移至 Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/)。

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

**Topics**
+ [先決條件](#driver-quickstart-golang.prereqs)
+ [步驟 1：安裝驅動程式](#driver-quickstart-golang.install)
+ [步驟 2：匯入套件](#driver-quickstart-golang.import)
+ [步驟 3：初始化驅動程式](#driver-quickstart-golang.initialize)
+ [步驟 4：建立資料表和索引](#driver-quickstart-golang.create-table-index)
+ [步驟 5：插入文件](#driver-quickstart-golang.insert)
+ [步驟 6：查詢文件](#driver-quickstart-golang.query)
+ [步驟 7：更新文件](#driver-quickstart-golang.update)
+ [步驟 8：查詢更新的文件](#driver-quickstart-golang.query-2)
+ [步驟 9：捨棄資料表](#driver-quickstart-golang.drop-table)
+ [執行完整的應用程式](#driver-quickstart-golang.complete)

## 先決條件
<a name="driver-quickstart-golang.prereqs"></a>

開始之前，請務必執行下列動作：

1. 如果您尚未執行此操作，請完成 Go 驅動程式[先決條件](getting-started.golang.md#getting-started.golang.prereqs)的 。這包括註冊 AWS、授予開發的程式設計存取權，以及安裝 Go。

1. 建立名為 的分類帳`quick-start`。

   若要了解如何建立分類帳，請參閱 主控台入門[步驟 1：建立新的分類帳](getting-started-step-1.md)中的 [Amazon QLDB 分類帳的基本操作](ledger-management.basics.md)或 。 **

## 步驟 1：安裝驅動程式
<a name="driver-quickstart-golang.install"></a>

確保您的專案使用 [Go 模組](https://blog.golang.org/using-go-modules)來安裝專案相依性。

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

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

安裝驅動程式也會安裝其相依性，包括 [適用於 Go 的 AWS SDK v2](https://github.com/aws/aws-sdk-go-v2) 和 [Amazon Ion](https://github.com/amzn/ion-go) 套件。

## 步驟 2：匯入套件
<a name="driver-quickstart-golang.import"></a>

匯入下列 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：初始化驅動程式
<a name="driver-quickstart-golang.initialize"></a>

初始化連接至名為 之分類帳的驅動程式執行個體`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：建立資料表和索引
<a name="driver-quickstart-golang.create-table-index"></a>

下列程式碼範例示範如何執行 `CREATE TABLE`和 `CREATE 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`，以及該資料表上 `firstName`和 `age` 欄位的索引。需要[索引](ql-reference.create-index.md)才能最佳化查詢效能，並協助限制[樂觀並行控制 (OCC)](concurrency.md) 衝突例外狀況。

## 步驟 5：插入文件
<a name="driver-quickstart-golang.insert"></a>

下列程式碼範例示範如何執行 `INSERT`陳述式。QLDB 支援 [PartiQL](ql-reference.md) 查詢語言 （與 SQL 相容） 和 [Amazon Ion](ion.md) 資料格式 (JSON 的超集）。

### 使用常值 PartiQL
<a name="driver-quickstart-golang.insert.partiql"></a>

下列程式碼使用字串常值 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 資料類型
<a name="driver-quickstart-golang.insert.ion"></a>

與 Go 的內建 [JSON 套件](https://golang.org/pkg/encoding/json/)類似，您可以在往返 Ion 之間合併和取消合併 Go 資料類型。

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

   ```
   type Person struct {
       FirstName string `ion:"firstName"`
       LastName  string `ion:"lastName"`
       Age       int    `ion:"age"`
   }
   ```

1. 建立 `Person` 的執行個體。

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

   驅動程式`person`會為您合併 的 Ion 編碼文字表示法。
**重要**  
若要讓 marshal 和 unmarshal 正常運作，必須匯出 Go 資料結構的欄位名稱 （大寫第一個字母）。

1. 將`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](ql-reference.insert.md)陳述式插入多個文件，您可以將類型[清單](driver-working-with-ion.md#driver-ion-list)的參數傳遞至陳述式，如下所示。  

   ```
   // people is a list
   txn.Execute("INSERT INTO People ?", people)
   ```
傳遞清單時，您不會將變數預留位置 (`?`) 括在雙角度括號 ( ) `<<...>>` 中。在手動 PartiQL 陳述式中，雙角括號表示稱為*包*的未排序集合。

## 步驟 6：查詢文件
<a name="driver-quickstart-golang.query"></a>

下列程式碼範例示範如何執行 `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：更新文件
<a name="driver-quickstart-golang.update"></a>

下列程式碼範例示範如何執行 `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：查詢更新的文件
<a name="driver-quickstart-golang.query-2"></a>

下列程式碼範例會查詢 `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：捨棄資料表
<a name="driver-quickstart-golang.drop-table"></a>

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

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

## 執行完整的應用程式
<a name="driver-quickstart-golang.complete"></a>

下列程式碼範例是應用程式的完整版本。您也可以從頭到尾複製並執行此程式碼範例，而不是個別執行上述步驟。此應用程式會在名為 的分類帳上示範一些基本 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)
    }
}
```