使用局部事务功能,创建数据范围在一个分区键值内的局部事务。对局部事务中的数据进行读写操作后,可以根据实际提交或者丢弃局部事务。局部事务通过悲观锁(Pessimistic Lock)实现并发控制。

目前局部事务功能处于邀测中,默认关闭。如果需要使用该功能,请提交工单进行申请或者加入钉钉群23307953(表格存储技术交流群-2)进行咨询。

使用局部事务可以指定某个分区键值内的操作是原子的,对分区键值内的数据进行的操作要么全部成功要么全部失败,并且所提供的隔离级别为读已提交。

前提条件

  • 已初始化OTSClient。具体操作,请参见初始化
  • 已创建数据表并写入数据。

使用方法

  1. 使用StartLocalTransaction在指定的分区键值创建一个局部事务,并获取局部事务ID。
  2. 对局部事务范围内的数据进行读写操作。

    支持对局部事务进行操作的接口为GetRow、PutRow、DeleteRow、UpdateRow、BatchWriteRow和GetRange。

  3. 使用CommitTransaction提交局部事务或者使用AbortTransaction丢弃局部事务。

限制

  • 每个局部事务从创建开始生命周期最长为60秒。

    如果超过60秒未提交或丢弃局部事务,表格存储服务端会认为此局部事务超时,并将局部事务丢弃。

  • 如果创建局部事务时超时,此请求可能在表格存储服务端已执行成功,此时用户需要等待该局部事务超时后重新创建。
  • 未提交的局部事务可能失效,如果出现此情况,需要重试该局部事务内的操作。
  • 在局部事务中读写数据有如下限制:
    • 不能使用局部事务ID访问局部事务范围(即创建时使用的分区键值)以外的数据。
    • 同一个局部事务中所有写请求的分区键值必须与创建局部事务时的分区键值相同,读请求则无此限制。
    • 一个局部事务同时只能用于一个请求中,在使用局部事务期间,其它使用此局部事务ID的操作均会失败。
    • 每个局部事务中两次读写操作的最大间隔为60秒。

      如果超过60秒未操作局部事务,表格存储服务端会认为此局部事务超时,并将局部事务丢弃。

    • 每个局部事务中写入的数据量最大为4 MB,按正常的写请求数据量计算规则累加。
    • 如果在局部事务中写入了未指定版本号的Cell,该Cell的版本号会在写入时(而非提交时)由表格存储服务端自动生成,生成规则与正常写入一个未指定版本号的Cell相同。
    • 如果BatchWriteRow请求中带有局部事务ID,则此请求中所有行只能操作该局部事务ID对应的表。
    • 在使用局部事务期间,对应分区键值的数据会被上写锁,只有持有局部事务ID在局部事务范围内的写请求才会成功。其它非事务请求或持有其他局部事务ID在局部事务范围内的写请求均会失败。在局部事务提交、丢弃或超时后,对应的锁也会被释放。
    • 带有局部事务ID的读写请求失败不会影响局部事务本身的存活情况,您可以指定重试规则进行重试或者主动丢弃当前局部事务。

参数

参数 说明
TableName 数据表名称。
PrimaryKey 数据表主键。
  • 创建局部事务时,只需要指定局部事务对应的分区键值。
  • 创建局部事务后,对局部事务范围内的数据进行读写操作时,需要指定完整主键。
TransactionId 局部事务ID,用于唯一标识一个局部事务。

创建局部事务后,操作局部事务时均需要带上局部事务ID。

示例

  1. 调用AsyncClient或SyncClient的startLocalTransaction方法使用指定分区键值创建一个局部事务,并获取局部事务ID。
    PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
    primaryKeyBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("txnKey"));
    PrimaryKey primaryKey = primaryKeyBuilder.build();
    StartLocalTransactionRequest request = new StartLocalTransactionRequest(tableName, primaryKey);
    String txnId = client.startLocalTransaction(request).getTransactionID();
  2. 对局部事务范围内的数据进行读写操作。

    对局部事务范围内数据的读写操作与正常读写数据操作基本相同,只需填入局部事务ID即可。

    • 写入一行数据。
      PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
      primaryKeyBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("txnKey"));
      primaryKeyBuilder.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong("userId"));
      PrimaryKey primaryKey = primaryKeyBuilder.build();
      RowPutChange rowPutChange = new RowPutChange(tableName, primaryKey);
      rowPutChange.addColumn(new Column("Col", ColumnValue.fromLong(columnValue)));
      
      PutRowRequest request = new PutRowRequest(rowPutChange);
      request.setTransactionId(txnId);
      client.putRow(request);
    • 读取此行数据。
      PrimaryKeyBuilder primaryKeyBuilder;
      primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
      primaryKeyBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("txnKey"));
      primaryKeyBuilder.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong("userId"));
      PrimaryKey primaryKey = primaryKeyBuilder.build();
      SingleRowQueryCriteria criteria = new SingleRowQueryCriteria(tableName, primaryKey);
      criteria.setMaxVersions(1); //设置读取最新版本的数据。
      
      GetRowRequest  request = new GetRowRequest(criteria);
      request.setTransactionId(txnId);
      GetRowResponse getRowResponse = client.getRow(request);
  3. 提交或丢弃局部事务。
    • 提交局部事务,使局部事务中的所有数据修改生效。
      CommitTransactionRequest commitRequest = new CommitTransactionRequest(txnId);
      client.commitTransaction(commitRequest);
    • 丢弃局部事务,局部事务中的所有数据修改均不会应用到原有数据。
      AbortTransactionRequest abortRequest = new AbortTransactionRequest(txnId);
      client.abortTransaction(abortRequest);