Use the Tablestore SDK for Go to run a local transaction within a partition key value so that all writes in the transaction are committed or discarded together. The isolation level is Read Committed.
Prerequisites
-
Install the Tablestore SDK for Go and initialize the client. Local transactions require version 1.7.8 or later. We recommend that you use the latest version.
-
Local transactions are enabled for the table. You can set
EnableLocalTxnwhen you create a table. To check whether local transactions are enabled for an existing table or to enable them, submit a ticket.
Description
A local transaction is limited to one partition key value. Reads and writes in the transaction share a transaction ID. The workflow has three stages:
-
Call
StartLocalTransactionwith a partition key value to create a local transaction and obtain its transaction ID. -
Call
GetRow,PutRow,UpdateRow,DeleteRow,BatchWriteRow, orGetRangein the transaction and include the transaction ID in each request. -
Call
CommitTransactionto apply all changes orAbortTransactionto discard the transaction and all changes.
func (client *TableStoreClient) StartLocalTransaction(request *StartLocalTransactionRequest) (*StartLocalTransactionResponse, error)
func (client *TableStoreClient) CommitTransaction(request *CommitTransactionRequest) (*CommitTransactionResponse, error)
func (client *TableStoreClient) AbortTransaction(request *AbortTransactionRequest) (*AbortTransactionResponse, error)
The following sample creates a local transaction for the user-a partition key value, writes a row in the transaction, and commits the transaction.
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)
}
Parameters
Create a local transaction
StartLocalTransactionRequest contains the following parameters.
|
Name |
Type |
Description |
|
TableName (required) |
|
The table name. |
|
PrimaryKey (required) |
|
The partition key value that defines the transaction scope. Specify only the first primary key column of the table. |
Data operations in a transaction
PutRowChange, UpdateRowChange, DeleteRowChange, SingleRowQueryCriteria, and RangeRowQueryCriteria contain the following common parameter when used in a transaction.
|
Name |
Type |
Description |
|
TransactionId (required) |
|
The local transaction ID returned by |
Commit or abort a local transaction
CommitTransactionRequest and AbortTransactionRequest contain the following parameter.
|
Name |
Type |
Description |
|
TransactionId (required) |
|
The local transaction ID to commit or abort. |
Response
StartLocalTransactionResponse contains the following business information.
|
Field |
Type |
Description |
|
|
|
The new local transaction ID, which is used in data operations and to commit or abort the transaction. |
Limitations
-
Auto-increment primary key columns and local transactions cannot be used together.
-
Local transactions use pessimistic locks for concurrency control. During a transaction, writes for the partition key value are locked. Only write requests that carry the transaction ID can succeed. The server releases the write lock when the transaction is committed, aborted, or times out.
-
A transaction can live for up to 60 seconds. If the interval between two operations exceeds 60 seconds, the server automatically aborts the transaction.
-
If a request to create a local transaction times out, the transaction may have already been created on the server. Wait for the transaction to time out before you create another transaction.
-
An uncommitted local transaction may become invalid. If this occurs, retry the operations in the transaction.
-
Only one request can use a transaction ID at a time. Concurrent requests that use the same transaction ID fail.
-
Write requests in the transaction must use the partition key value that was used to create the transaction. Read requests are not subject to this restriction.
-
When you use
BatchWriteRowto write rows in a transaction, all rows in the request must belong to the table for which the transaction was created. -
A transaction can write up to 4 MB of data. The amount of data is accumulated based on the calculation rules for regular write requests.
-
If no version is specified for an attribute column, the server generates the version based on the rules for regular writes when the data is written, not when the transaction is committed.
-
A failed read or write does not invalidate the transaction. You can retry the request or abort the transaction.
Examples
Read a row in a local transaction
The following sample reads a row in an existing local transaction. For a read-only transaction, committing and aborting have the same effect: both release the transaction.
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)
}