Go SDK 可在指定分区键值范围内执行局部事务,使事务内的写操作全部提交或全部丢弃,隔离级别为读已提交(Read Committed)。
前提条件
-
安装Tablestore Go SDK并初始化客户端。局部事务需要 1.7.8 及以上版本,建议使用最新版本。
-
数据表已开启局部事务。创建数据表时可通过
EnableLocalTxn开启;如果需要确认已有数据表是否开启局部事务,或为已有数据表开启该功能,请提交工单或加入钉钉技术交流群36165029092。
功能说明
局部事务的作用范围限定在单个分区键值内。事务内的读写请求共享同一个事务 ID,操作分为以下三个阶段:
-
调用
StartLocalTransaction并传入分区键值,创建局部事务并获取事务 ID。 -
在事务内执行
GetRow、PutRow、UpdateRow、DeleteRow、BatchWriteRow或GetRange,并在请求中携带事务 ID。 -
调用
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(必选) |
|
数据表名称。 |
|
PrimaryKey(必选) |
|
用于限定事务范围的分区键值。只设置数据表的第一个主键列。 |
事务内数据操作
事务内的 PutRowChange、UpdateRowChange、DeleteRowChange、SingleRowQueryCriteria 或 RangeRowQueryCriteria 包含以下公共参数。
|
名称 |
类型 |
说明 |
|
TransactionId(必选) |
|
|
提交或丢弃局部事务
CommitTransactionRequest 和 AbortTransactionRequest 包含以下参数。
|
名称 |
类型 |
说明 |
|
TransactionId(必选) |
|
要提交或丢弃的局部事务 ID。 |
返回值
StartLocalTransactionResponse 包含以下业务信息。
|
字段 |
类型 |
说明 |
|
|
|
新建的局部事务 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)
}