局部事务

更新时间:
复制 MD 格式

Go SDK 可在指定分区键值范围内执行局部事务,使事务内的写操作全部提交或全部丢弃,隔离级别为读已提交(Read Committed)。

前提条件

  • 安装Tablestore Go SDK并初始化客户端。局部事务需要 1.7.8 及以上版本,建议使用最新版本。

  • 数据表已开启局部事务。创建数据表时可通过 EnableLocalTxn 开启;如果需要确认已有数据表是否开启局部事务,或为已有数据表开启该功能,请提交工单或加入钉钉技术交流群36165029092

功能说明

局部事务的作用范围限定在单个分区键值内。事务内的读写请求共享同一个事务 ID,操作分为以下三个阶段:

  1. 调用 StartLocalTransaction 并传入分区键值,创建局部事务并获取事务 ID。

  2. 在事务内执行 GetRowPutRowUpdateRowDeleteRowBatchWriteRowGetRange,并在请求中携带事务 ID。

  3. 调用 CommitTransaction 提交事务使修改生效,或调用 AbortTransaction 丢弃事务和所有修改。

func (client *TableStoreClient) StartLocalTransaction(request *StartLocalTransactionRequest) (*StartLocalTransactionResponse, error)
func (client *TableStoreClient) CommitTransaction(request *CommitTransactionRequest) (*CommitTransactionResponse, error)
func (client *TableStoreClient) AbortTransaction(request *AbortTransactionRequest) (*AbortTransactionResponse, error)

以下示例为分区键值 user-a 创建局部事务,在事务内写入一行数据,然后提交事务。

partitionKey := &tablestore.PrimaryKey{}
partitionKey.AddPrimaryKeyColumn("user_id", "user-a")

startResponse, err := client.StartLocalTransaction(
    &tablestore.StartLocalTransactionRequest{
        TableName:  "example_table",
        PrimaryKey: partitionKey,
    },
)
if err != nil {
    log.Fatal(err)
}
transactionID := startResponse.TransactionId

rowKey := &tablestore.PrimaryKey{}
rowKey.AddPrimaryKeyColumn("user_id", "user-a")
rowKey.AddPrimaryKeyColumn("record_id", int64(1))

change := &tablestore.PutRowChange{
    TableName:     "example_table",
    PrimaryKey:    rowKey,
    TransactionId: transactionID,
}
change.AddColumn("status", "created")
change.SetCondition(tablestore.RowExistenceExpectation_IGNORE)

_, err = client.PutRow(&tablestore.PutRowRequest{PutRowChange: change})
if err != nil {
    _, _ = client.AbortTransaction(
        &tablestore.AbortTransactionRequest{TransactionId: transactionID},
    )
    log.Fatal(err)
}

_, err = client.CommitTransaction(
    &tablestore.CommitTransactionRequest{TransactionId: transactionID},
)
if err != nil {
    log.Fatal(err)
}

参数说明

创建局部事务

StartLocalTransactionRequest 包含以下参数。

名称

类型

说明

TableName(必选)

string

数据表名称。

PrimaryKey(必选)

*PrimaryKey

用于限定事务范围的分区键值。只设置数据表的第一个主键列。

事务内数据操作

事务内的 PutRowChangeUpdateRowChangeDeleteRowChangeSingleRowQueryCriteriaRangeRowQueryCriteria 包含以下公共参数。

名称

类型

说明

TransactionId(必选)

*string

StartLocalTransaction 返回的局部事务 ID。事务内的每个读写请求都必须携带。

提交或丢弃局部事务

CommitTransactionRequestAbortTransactionRequest 包含以下参数。

名称

类型

说明

TransactionId(必选)

*string

要提交或丢弃的局部事务 ID。

返回值

StartLocalTransactionResponse 包含以下业务信息。

字段

类型

说明

TransactionId

*string

新建的局部事务 ID,用于事务内的数据操作以及提交或丢弃事务。

使用限制

  • 主键列自增和局部事务不能同时使用。

  • 局部事务通过悲观锁实现并发控制。事务期间,指定分区键值的数据会被加写锁,只有携带该事务 ID 的写请求可以成功。提交、丢弃或超时后,服务端释放写锁。

  • 事务生命周期最长为 60 秒。两次操作间隔超过 60 秒时,服务端自动丢弃事务。

  • 创建局部事务时如果请求超时,事务可能已在服务端创建成功。等待该事务超时后,再重新创建事务。

  • 未提交的局部事务可能失效。如果事务失效,需要重试事务内的操作。

  • 同一时间只能有一个请求使用事务 ID,并发使用同一事务 ID 的请求均失败。

  • 事务内写请求的分区键值必须与创建事务时一致;读请求不受此限制。

  • 使用 BatchWriteRow 在事务内批量写入时,请求中的所有行只能操作该事务对应的数据表。

  • 单个事务最多写入 4 MB 数据,数据量按普通写请求的计算规则累加。

  • 事务内写入属性列时未指定版本号的,版本号在写入时由服务端按普通写入的规则生成,而不是在提交事务时生成。

  • 事务内读写请求失败不会使事务失效,可以重试请求或主动丢弃事务。

场景示例

在局部事务内读取一行数据

以下示例在已创建的局部事务内读取一行数据。只读事务的提交和丢弃效果相同,都会释放事务。

criteria := &tablestore.SingleRowQueryCriteria{
    TableName:     "example_table",
    PrimaryKey:    rowKey,
    MaxVersion:    1,
    TransactionId: transactionID,
}
response, err := client.GetRow(
    &tablestore.GetRowRequest{SingleRowQueryCriteria: criteria},
)
if err != nil {
    log.Fatal(err)
}
fmt.Println(response.Columns)

_, err = client.CommitTransaction(
    &tablestore.CommitTransactionRequest{TransactionId: transactionID},
)
if err != nil {
    log.Fatal(err)
}