赛尔校园公共服务平台 Logo
平台使用
阿里云
百度云
移动云
智算服务
教育生态
登录 →
赛尔校园公共服务平台 Logo
平台使用 阿里云 百度云 移动云 智算服务 教育生态
登录
  1. 首页
  2. 阿里云
  3. 表格存储
  4. 开发参考
  5. SDK参考
  6. Go SDK
  7. 表操作
  8. 局部事务

局部事务

  • 表操作
  • 发布于 2025-04-22
  • 0 次阅读
文档编辑
文档编辑

为数据表开启局部事务后,使用局部事务功能,您可以创建数据范围在一个分区键值内的局部事务并对局部事务中的数据进行读写操作。通过使用局部事务您可以实现单行或多行读写的原子操作。

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

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

前提条件

  • 已初始化Client。具体操作,请参见初始化OTSClient。

  • 已创建数据表并写入数据。

使用方法

  1. 使用StartLocalTransaction在指定的分区键值创建一个局部事务,并获取局部事务ID。

  2. 对局部事务范围内的数据进行读写操作。

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

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

注意事项

  • 主键自增列功能和局部事务功能不能同时使用。

  • 局部事务通过悲观锁(Pessimistic Lock)实现并发控制。

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

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

  • 如果创建局部事务时超时,则请求可能在表格存储服务端已执行成功,此时请等待该局部事务超时后重新创建。

  • 未提交的局部事务可能会失效,如果出现此情况,则需要重试该局部事务内的操作。

  • 如果未对局部事务范围内的数据进行写操作,则提交局部事务或丢弃局部事务的操作是等同的。

  • 在局部事务中读写数据有如下限制:

    • 不能使用局部事务ID访问局部事务范围(即创建时使用的分区键值)以外的数据。

    • 同一个局部事务中所有写请求的分区键值必须与创建局部事务时的分区键值相同,读请求则无此限制。

    • 一个局部事务同时只能用于一个请求中,在使用局部事务期间,其他使用此局部事务ID的操作均会失败。

    • 每个局部事务中两次读写操作的最大间隔为60秒。

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

    • 每个局部事务中写入的数据量最大为4 MB,按正常的写请求数据量计算规则累加。

    • 如果在局部事务中写入了未指定版本号的Cell,则该Cell的版本号会在写入数据时(而非提交局部事务时)由表格存储服务端自动生成,生成规则与正常写入一个未指定版本号的Cell相同。

    • 如果BatchWriteRow请求中带有局部事务ID,则此请求中所有行只能操作该局部事务ID对应的表。

    • 在使用局部事务期间,对应分区键值的数据会被加上写锁,只有持有局部事务ID在局部事务范围内的写请求才会成功。其他非事务请求或持有其他局部事务ID在局部事务范围内的写请求均会失败。在局部事务提交、丢弃或超时后,对应的锁也会被释放。

    • 带有局部事务ID的读写请求失败不会影响局部事务本身的存活情况,您可以指定重试规则进行重试或者主动丢弃当前局部事务。

参数

参数

是否必选

说明

TableName

是

数据表名称。

PrimaryKey

是

数据表主键。

  • 创建局部事务时,只需要指定局部事务对应的分区键值。

  • 创建局部事务后,对局部事务范围内的数据进行读写操作时,需要指定完整主键。

TransactionId

是

局部事务ID,用于唯一标识一个局部事务。

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

示例

使用局部事务写入一行数据

以下示例用于为表的指定分区键创建一个局部事务后,在局部事务内写入一行数据。如果数据写入成功,则提交事务;如果数据写入失败,则丢弃事务。

func transactionPutRow(client *tablestore.TableStoreClient, tableName string) {
    //局部事务需要指定一个分区键(第一列主键)。
    transPk := new(tablestore.PrimaryKey)
    transPk.AddPrimaryKeyColumn("pk1", "pk1value")
    trans := &tablestore.StartLocalTransactionRequest{
        TableName:  tableName,
        PrimaryKey: transPk,
    }
    response, err := client.StartLocalTransaction(trans)
    if err != nil {
        fmt.Println("failed to create transaction", err)
        return
    }
    //获取局部事务ID。
    transId := response.TransactionId

    putPk := new(tablestore.PrimaryKey)
    putPk.AddPrimaryKeyColumn("pk1", "pk1value")
    putPk.AddPrimaryKeyColumn("pk2", int64(4))
    putRowChange := &tablestore.PutRowChange{
        TableName:  tableName,
        PrimaryKey: putPk,
    }
    putRowChange.AddColumn("col1", "col1data1")
    putRowChange.AddColumn("col2", int64(3))
    putRowChange.AddColumn("col3", []byte("test"))
    putRowChange.SetCondition(tablestore.RowExistenceExpectation_IGNORE)
    //设置局部事务ID,局部事务ID可以通过StartLocalTransactionResponse.TransactionId获取。
    putRowChange.TransactionId = transId
    putRowRequest := &tablestore.PutRowRequest{
        PutRowChange: putRowChange,
    }
    _, err = client.PutRow(putRowRequest)
    if err != nil {
        //如果数据写入失败,则丢弃事务,局部事务中的所有数据修改均不会应用到原有数据。
        fmt.Println("putrow failed with error:", err)
        request := &tablestore.AbortTransactionRequest{
            TransactionId: transId,
        }
        abortResponse, err := client.AbortTransaction(request)
        if err != nil {
            fmt.Println("abort transaction failed with error:", err)
        } else {
            fmt.Println("abort transaction finished. RequestId is", abortResponse.RequestId)
        }
    } else {
        //如果数据写入成功,则提交事务,使局部事务中的所有数据修改生效。您也可以通过丢弃事务来使数据写入不生效。
        fmt.Println("putrow finished")
        request := &tablestore.CommitTransactionRequest{
            TransactionId: transId,
        }
        commitResponse, err := client.CommitTransaction(request)
        if err != nil {
            fmt.Println("commit transaction failed with error:", err)
        } else {
            fmt.Println("commit transaction finished. RequestId is", commitResponse.RequestId)
        }
    }
}

使用局部事务读取一行数据

以下示例用于为表的指定分区键创建一个局部事务后,在局部事务内读取一行数据。

func transactionGetRow(client *tablestore.TableStoreClient, tableName string) {
    //局部事务需要指定一个分区键(第一列主键)。
    transPk := new(tablestore.PrimaryKey)
    transPk.AddPrimaryKeyColumn("pk1", "pk1value")
    trans := &tablestore.StartLocalTransactionRequest{
        TableName:  tableName,
        PrimaryKey: transPk,
    }
    response, err := client.StartLocalTransaction(trans)
    if err != nil {
        fmt.Println("failed to create transaction", err)
        return
    }
    //获取局部事务ID。
    transId := response.TransactionId

    //读取数据。
    getRowPk := new(tablestore.PrimaryKey)
    getRowPk.AddPrimaryKeyColumn("pk1", "pk1value")
    getRowPk.AddPrimaryKeyColumn("pk2", int64(18))
    criteria := &tablestore.SingleRowQueryCriteria{
        PrimaryKey: getRowPk,
        TableName:  tableName,
        //设置读取最新版本的数据。
        MaxVersion: 1,
        //设置局部事务ID。
        TransactionId: transId,
    }
    getRowRequest := &tablestore.GetRowRequest{
        SingleRowQueryCriteria: criteria,
    }
    getResp, err := client.GetRow(getRowRequest)
    if err != nil {
        fmt.Println("getrow failed with error:", err)
    } else {
        fmt.Println("get row col0 result is ", getResp.Columns[0].ColumnName, getResp.Columns[0].Value)
    }

    //提交或丢弃局部事务。对于读操作来说,提交局部事务或丢弃局部事务的操作是等同的。
    //提交局部事务,使局部事务中的所有数据修改生效。
    request := &tablestore.CommitTransactionRequest{
        TransactionId: transId,
    }
    commitResponse, err := client.CommitTransaction(request)
    if err != nil {
        fmt.Println("commit transaction failed with error:", err)
    } else {
        fmt.Println("commit transaction finished. RequestId is", commitResponse.RequestId)
    }
    //丢弃局部事务,局部事务中的所有数据修改均不会应用到原有数据。
    //request := &tablestore.AbortTransactionRequest{
    //    TransactionId: transId,
    //}
    //abortResponse, err := client.AbortTransaction(request)
    //if err != nil {
    //    fmt.Println("abort transaction failed with error:", err)
    //} else {
    //    fmt.Println("abort transaction finished. RequestId is", abortResponse.RequestId)
    //}
}

相关文档

如果要在局部事务内进行批量写入、范围读取等操作,请在创建局部事务后,使用写入数据或者读取数据文档中的相应操作示例以及在请求中带上局部事务ID实现。

相关文章

创建数据表 2025-04-22 14:26

本文将通过参数说明和示例代码为您介绍如何使用 Go SDK 创建数据表。在创建数据表时,您需要指定数据表的结构信息和配置信息。CU 模式(原按量模式)下高性能型实例中的数据表还可以根据需要设置预留读写吞吐量。

创建加密表 2025-04-22 14:26

本文将通过参数说明和示例代码为您介绍如何使用 Go SDK 创建加密数据表,实现数据加密存储功能。表格存储提供两种加密方式:基于密钥管理服务(Key Management Service,简称 KMS)的密钥加密和基于自带密钥(Bring Your Own Key,简称 BYOK)的自定义密钥加密。

更新表配置 2025-04-22 14:26

本文将通过参数说明和示例代码为您介绍如何使用 Go SDK 更新表配置。在更新数据表时,您可以修改表的配置信息(例如数据生命周期、最大版本数、有效版本偏差等)和 Stream 配置。此外,您还可以为 CU 模式(原按量模式)下高性能型实例中数据表调整预留读写吞吐量。

列出表名称 2025-04-22 14:26

使用ListTable接口获取当前实例下已创建的所有表的表名。 前提条件

预定义列操作 2025-04-22 14:26

预定义列是为数据表预先定义一些非主键列以及其类型。为数据表设置预定义列后,在创建二级索引时,您可以将预定义列作为索引表的索引列或者属性列。如果不再使用某些预定义列,您可以删除相应预定义列。 注意事项 只有使用二级索引时才需要为数据表添加

查询表描述信息 2025-04-22 14:26

使用DescribeTable接口可以查询指定表的结构、预留读/写吞吐量详情等信息。 前提条件

目录
Copyright © 2025 your company All Rights Reserved. Powered by 赛尔网络.
京ICP备14022346号-15
gongan beian 京公网安备11010802041014号