全部產品
Search
文件中心

Tablestore:局部事務

更新時間:Jun 30, 2024

為資料表開啟局部事務後,使用局部事務功能,您可以建立資料範圍在一個分區索引值內的局部事務並對局部事務中的資料進行讀寫操作。通過使用局部事務您可以實現單行或多行讀寫的原子操作。

使用局部事務可以指定某個分區索引值內的操作是原子的,對分區索引值內的資料進行的操作要麼全部成功要麼全部失敗,並且所提供的隔離等級為讀已提交。

前提條件

  • 已初始化Client。具體操作,請參見初始化OTSClient

  • 已建立資料表並寫入資料。

使用方法

  1. 使用StartLocalTransaction在指定的分區索引值建立一個局部事務,並擷取局部事務ID。

  2. 對局部事務範圍內的資料進行讀寫操作。

    支援對局部事務進行操作的介面為GetRow、PutRow、DeleteRow、UpdateRow、BatchWriteRow和GetRange。

  3. 使用CommitTransaction提交局部事務或者使用AbortTransaction丟棄局部事務。

注意事項

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

  • 局部事務通過悲觀鎖(Pessimistic Lock)實現並發控制。

  • 每個局部事務從建立開始生命週期最長為60秒。

    如果超過60秒未提交局部事務或丟棄局部事務,則Table Store服務端會認為此局部事務逾時,並將局部事務丟棄。

  • 如果建立局部事務時逾時,則請求可能在Table Store服務端已執行成功,此時請等待該局部事務逾時後重新建立。

  • 未提交的局部事務可能會失效,如果出現此情況,則需要重試該局部事務內的操作。

  • 如果未對局部事務範圍內的資料進行寫操作,則提交局部事務或丟棄局部事務的操作是等同的。

  • 在局部事務中讀寫資料有如下限制:

    • 不能使用局部事務ID訪問局部事務範圍(即建立時使用的分區索引值)以外的資料。

    • 同一個局部事務中所有寫請求的分區索引值必須與建立局部事務時的分區索引值相同,讀請求則無此限制。

    • 一個局部事務同時只能用於一個請求中,在使用局部事務期間,其他使用此局部事務ID的操作均會失敗。

    • 每個局部事務中兩次讀寫操作的最大間隔為60秒。

      如果超過60秒未操作局部事務,則Table Store服務端會認為此局部事務逾時,並將局部事務丟棄。

    • 每個局部事務中寫入的資料量最大為4 MB,按正常的寫請求資料量計算規則累加。

    • 如果在局部事務中寫入了未指定版本號碼的Cell,則該Cell的版本號碼會在寫入資料時(而非提交局部事務時)由Table Store服務端自動產生,建置規則與正常寫入一個未指定版本號碼的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實現。