局部事務

更新時間:
Copy as MD

Java SDK 在指定分區索引值範圍內建立局部事務,事務內的所有操作要麼全部成功要麼全部失敗(隔離等級為讀已提交 Read Committed),適用於實現單行或多行的原子讀寫。

前提條件

  • 安裝 Tablestore Java SDK並初始化用戶端。

  • 已為資料表開啟局部事務功能。

    說明

    建立資料表時如果未啟用局部事務,建表後需要使用局部事務功能,或者需要查看錶是否開啟局部事務,請提交工單

功能說明

// 在 SyncClient 上調用
public StartLocalTransactionResponse startLocalTransaction(StartLocalTransactionRequest request) throws TableStoreException, ClientException
public CommitTransactionResponse commitTransaction(CommitTransactionRequest request) throws TableStoreException, ClientException
public AbortTransactionResponse abortTransaction(AbortTransactionRequest request) throws TableStoreException, ClientException

// 在事務請求(繼承 TxnRequest)上攜帶事務 ID
public void setTransactionId(String transactionId)

局部事務的作用範圍限定在單個分區索引值內。事務內的所有讀寫請求共用同一個事務 ID,Table Store通過該 ID 保證原子性和隔離性。三個核心介面配合使用:

  • startLocalTransaction(StartLocalTransactionRequest):傳入分區索引值,建立局部事務並擷取事務 ID。

  • 在事務內執行讀寫操作,每個請求需通過 setTransactionId(txnId) 攜帶事務 ID。支援的操作:GetRow / PutRow / UpdateRow / DeleteRow / BatchWriteRow / GetRange

  • commitTransaction(CommitTransactionRequest) 提交事務使修改生效;或 abortTransaction(AbortTransactionRequest) 丟棄事務放棄所有修改。

以下樣本為分區索引值 pkvalue 建立局部事務,在事務內寫入主鍵為 (pkvalue, 10001) 的一行資料,然後提交事務。

String tableName = "local_tx_demo";

// 1. 為指定分區索引值建立局部事務,擷取事務 ID
PrimaryKeyBuilder pkBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
pkBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("pkvalue"));
PrimaryKey partitionKey = pkBuilder.build();

StartLocalTransactionRequest startRequest =
        new StartLocalTransactionRequest(tableName, partitionKey);
String txnId = client.startLocalTransaction(startRequest).getTransactionID();

// 2. 在事務內寫入一行資料,需指定完整主鍵並攜帶事務 ID
PrimaryKeyBuilder rowKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
rowKeyBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("pkvalue"));
rowKeyBuilder.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong(10001));
PrimaryKey rowKey = rowKeyBuilder.build();

RowPutChange rowPutChange = new RowPutChange(tableName, rowKey);
rowPutChange.addColumn(new Column("col1", ColumnValue.fromString("colvalue")));
rowPutChange.addColumn(new Column("col2", ColumnValue.fromLong(10)));

PutRowRequest putRequest = new PutRowRequest(rowPutChange);
putRequest.setTransactionId(txnId);
client.putRow(putRequest);

// 3. 提交事務使所有寫入生效;如需放棄修改,調用 abortTransaction()
CommitTransactionRequest commitRequest = new CommitTransactionRequest(txnId);
client.commitTransaction(commitRequest);

參數說明

名稱

類型

說明

tableName(必選)

String

資料表名稱。

primaryKey(必選)

PrimaryKey

資料表主鍵。

  • 建立局部事務時,只需指定分區索引值。

  • 在事務內執行讀寫操作時,需要指定完整主鍵(所有主鍵列)。

transactionId(必選)

String

局部事務 ID,由 startLocalTransaction 返回,用於唯一標識一個局部事務。

事務內的每個讀寫請求都需通過 setTransactionId(txnId) 攜帶該 ID。

使用限制

  • 主鍵自增列與局部事務功能不能同時使用。

  • 局部事務通過悲觀鎖(Pessimistic Lock)實現並發控制;事務期間分區索引值的資料加寫鎖,僅持有事務 ID 的寫請求成功。

  • 事務生命週期最長 60 秒;兩次操作間隔超過 60 秒視為逾時,服務端自動丟棄。

  • 同一事務只能用於一個請求,並發使用同一事務 ID 的操作均失敗。

  • 事務內寫請求的分區索引值必須與建立事務時一致;讀請求無此限制。

  • 單個事務寫入資料量最大 4 MB。

  • 事務內寫入列值時未指定版本號碼(timestamp)的,版本號碼在寫入資料時(而非提交事務時)由服務端自動產生,規則與普通寫入一致。

  • BatchWriteRow 請求攜帶事務 ID 時,所有行只能操作該事務對應的表。

  • 未對範圍內資料執行寫操作時,提交與丟棄等同。

  • 帶事務 ID 的讀寫請求失敗不影響事務存活,可指定重試規則或主動丟棄。

情境樣本

事務內讀取一行

為指定分區鍵建立唯讀事務,讀取一行資料。對於唯讀事務,提交和丟棄的效果相同,均會釋放事務。

String tableName = "local_tx_demo";

// 1. 為指定分區索引值建立局部事務
PrimaryKeyBuilder pkBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
pkBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("pkvalue"));
PrimaryKey partitionKey = pkBuilder.build();

StartLocalTransactionRequest startRequest =
        new StartLocalTransactionRequest(tableName, partitionKey);
String txnId = client.startLocalTransaction(startRequest).getTransactionID();

// 2. 在事務內讀取一行資料,需指定完整主鍵並攜帶事務 ID
PrimaryKeyBuilder rowKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
rowKeyBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("pkvalue"));
rowKeyBuilder.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong(10001));
PrimaryKey rowKey = rowKeyBuilder.build();

SingleRowQueryCriteria criteria = new SingleRowQueryCriteria(tableName, rowKey);
criteria.setMaxVersions(1);

GetRowRequest getRequest = new GetRowRequest(criteria);
getRequest.setTransactionId(txnId);
GetRowResponse getResponse = client.getRow(getRequest);

// 3. 提交或丟棄事務。對於唯讀事務,兩者效果相同,均會釋放事務
CommitTransactionRequest commitRequest = new CommitTransactionRequest(txnId);
client.commitTransaction(commitRequest);

Row row = getResponse.getRow();
System.out.println(row);

事務內批量寫入多行

通過 BatchWriteRowRequest.setTransactionId(txnId) 在批量寫入中攜帶事務 ID。所有行的分區索引值必須與建立事務時一致,單次提交原子生效。

String tableName = "local_tx_demo";

// 1. 建立局部事務,所有批量行的分區索引值必須與此一致
PrimaryKeyBuilder pkBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
pkBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("pkvalue"));
PrimaryKey partitionKey = pkBuilder.build();

StartLocalTransactionRequest startRequest =
        new StartLocalTransactionRequest(tableName, partitionKey);
String txnId = client.startLocalTransaction(startRequest).getTransactionID();

// 2. 構造批量寫入請求,攜帶事務 ID
BatchWriteRowRequest batchRequest = new BatchWriteRowRequest();
batchRequest.setTransactionId(txnId);

// 添加多行(所有行的 pk1 必須等於事務的分區索引值 "pkvalue")
for (long pk2 = 20001; pk2 <= 20003; pk2++) {
    PrimaryKeyBuilder rowKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    rowKeyBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("pkvalue"));
    rowKeyBuilder.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong(pk2));
    RowPutChange rowPutChange = new RowPutChange(tableName, rowKeyBuilder.build());
    rowPutChange.addColumn(new Column("col1", ColumnValue.fromString("batch_" + pk2)));
    batchRequest.addRowChange(rowPutChange);
}

BatchWriteRowResponse batchResponse = client.batchWriteRow(batchRequest);
System.out.println("Batch all succeeded: " + batchResponse.isAllSucceed());

// 3. 提交事務,使所有批量寫入原子生效
CommitTransactionRequest commitRequest = new CommitTransactionRequest(txnId);
client.commitTransaction(commitRequest);

相關文檔