Use local transactions

Updated at:

Use Tablestore SDK for Python to group reads and writes for one partition key value into an atomic operation whose writes are all committed or all discarded.

Prerequisites

  • Install the Tablestore SDK for Python and initialize a client.

  • Local transactions are enabled for the table.

    Note

    To enable local transactions for an existing table or check whether the feature is enabled, submit a ticket or join DingTalk technical support group 36165029092.

Function description

A local transaction is scoped to one partition key value and uses the Read Committed isolation level. Requests in the transaction share a transaction ID. Use a local transaction as follows:

  1. Call start_local_transaction with the partition key value to obtain a transaction ID.

  2. Call get_row, put_row, update_row, delete_row, batch_write_row, or get_range in the transaction and pass the ID in transaction_id.

  3. Call commit_transaction to commit all writes or abort_transaction to discard all writes.

def start_local_transaction(self, table_name, key)
def commit_transaction(self, transaction_id)
def abort_transaction(self, transaction_id)

The following example starts a local transaction for the partition key value device, writes a row, and commits the transaction.

table_name = "example_table"
partition_key = [("partition", "device")]
transaction_id = client.start_local_transaction(table_name, partition_key)

primary_key = [("partition", "device"), ("id", 1)]
row = Row(primary_key, [("status", "online")])
condition = Condition(RowExistenceExpectation.IGNORE)
client.put_row(
    table_name,
    row,
    condition,
    transaction_id=transaction_id,
)

client.commit_transaction(transaction_id)

Parameters

A local transaction contains the following key parameters.

Name

Type

Description

table_name (required)

str

The name of the table.

key (required)

List[Tuple]

The partition key used to start the local transaction. Specify only the name and value of the first primary key column.

primary_key (required)

List[Tuple]

The complete primary key used to read or write a row in the transaction. Specify all primary key columns. For writes, the partition key value must match key.

transaction_id (required)

str

The local transaction ID returned by start_local_transaction. Pass the ID to every read, write, commit, or abort request in the transaction.

Limits

  • Local transactions are not compatible with auto-increment primary key columns.

  • Local transactions use pessimistic locking. During a transaction, a write lock is held on data for the partition key value, and only writes that carry the transaction ID can succeed.

  • A transaction has a maximum lifetime of 60 seconds. If two consecutive operations are more than 60 seconds apart, the transaction times out and the server discards it.

  • A transaction ID can be used by only one request at a time. Concurrent requests that share the ID all fail.

  • Every write in a transaction must use the partition key value that started the transaction. Reads have no such restriction.

  • A single transaction can write up to 4 MB of data.

  • If an attribute column write does not specify a data version, the server generates the version at write time, not at commit time.

  • When a BatchWriteRowRequest carries a transaction ID, all rows must target the table on which the transaction was started.

  • If a transaction contains no writes, commit and abort have the same effect and both release the transaction.

  • A failed read or write that carries a transaction ID does not end the transaction. Retry the request or abort the transaction explicitly.

Examples

Read a row in a transaction

The following example reads a row in a local transaction. For a read-only transaction, commit and abort have the same effect.

table_name = "example_table"
partition_key = [("partition", "device")]
transaction_id = client.start_local_transaction(table_name, partition_key)

primary_key = [("partition", "device"), ("id", 1)]
consumed, return_row, next_token = client.get_row(
    table_name,
    primary_key,
    transaction_id=transaction_id,
)
print(return_row.primary_key, return_row.attribute_columns)

client.commit_transaction(transaction_id)

Batch write rows in a transaction

The following example calls set_transaction_id to include the transaction ID in a batch request. The partition key value of every row must match the value used to start the transaction.

table_name = "example_table"
partition_key = [("partition", "device")]
transaction_id = client.start_local_transaction(table_name, partition_key)

condition = Condition(RowExistenceExpectation.IGNORE)
row_items = [
    PutRowItem(Row([("partition", "device"), ("id", 2)], [("status", "online")]), condition),
    PutRowItem(Row([("partition", "device"), ("id", 3)], [("status", "offline")]), condition),
]
request = BatchWriteRowRequest()
request.add(TableInBatchWriteRowItem(table_name, row_items))
request.set_transaction_id(transaction_id)

response = client.batch_write_row(request)
if response.is_all_succeed():
    client.commit_transaction(transaction_id)
else:
    client.abort_transaction(transaction_id)