局部事務(wù)
為數(shù)據(jù)表開(kāi)啟局部事務(wù)后,使用局部事務(wù)功能,您可以創(chuàng)建數(shù)據(jù)范圍在一個(gè)分區(qū)鍵值內(nèi)的局部事務(wù)并對(duì)局部事務(wù)中的數(shù)據(jù)進(jìn)行讀寫(xiě)操作。通過(guò)使用局部事務(wù)您可以實(shí)現(xiàn)單行或多行讀寫(xiě)的原子操作。
目前局部事務(wù)功能處于邀測(cè)中,默認(rèn)關(guān)閉。如果需要使用該功能,請(qǐng)提交工單進(jìn)行申請(qǐng)或者加入釘釘群36165029092(表格存儲(chǔ)技術(shù)交流群-3)進(jìn)行咨詢。
使用局部事務(wù)可以指定某個(gè)分區(qū)鍵值內(nèi)的操作是原子的,對(duì)分區(qū)鍵值內(nèi)的數(shù)據(jù)進(jìn)行的操作要么全部成功要么全部失敗,并且所提供的隔離級(jí)別為讀已提交。
前提條件
已初始化Client。具體操作,請(qǐng)參見(jiàn)初始化OTSClient。
已創(chuàng)建數(shù)據(jù)表并寫(xiě)入數(shù)據(jù)。
使用方法
使用StartLocalTransaction在指定的分區(qū)鍵值創(chuàng)建一個(gè)局部事務(wù),并獲取局部事務(wù)ID。
對(duì)局部事務(wù)范圍內(nèi)的數(shù)據(jù)進(jìn)行讀寫(xiě)操作。
支持對(duì)局部事務(wù)進(jìn)行操作的接口為GetRow、PutRow、DeleteRow、UpdateRow、BatchWriteRow和GetRange。
使用CommitTransaction提交局部事務(wù)或者使用AbortTransaction丟棄局部事務(wù)。
注意事項(xiàng)
主鍵自增列功能和局部事務(wù)功能不能同時(shí)使用。
局部事務(wù)通過(guò)悲觀鎖(Pessimistic Lock)實(shí)現(xiàn)并發(fā)控制。
每個(gè)局部事務(wù)從創(chuàng)建開(kāi)始生命周期最長(zhǎng)為60秒。
如果超過(guò)60秒未提交局部事務(wù)或丟棄局部事務(wù),則表格存儲(chǔ)服務(wù)端會(huì)認(rèn)為此局部事務(wù)超時(shí),并將局部事務(wù)丟棄。
如果創(chuàng)建局部事務(wù)時(shí)超時(shí),則請(qǐng)求可能在表格存儲(chǔ)服務(wù)端已執(zhí)行成功,此時(shí)請(qǐng)等待該局部事務(wù)超時(shí)后重新創(chuàng)建。
未提交的局部事務(wù)可能會(huì)失效,如果出現(xiàn)此情況,則需要重試該局部事務(wù)內(nèi)的操作。
如果未對(duì)局部事務(wù)范圍內(nèi)的數(shù)據(jù)進(jìn)行寫(xiě)操作,則提交局部事務(wù)或丟棄局部事務(wù)的操作是等同的。
在局部事務(wù)中讀寫(xiě)數(shù)據(jù)有如下限制:
不能使用局部事務(wù)ID訪問(wèn)局部事務(wù)范圍(即創(chuàng)建時(shí)使用的分區(qū)鍵值)以外的數(shù)據(jù)。
同一個(gè)局部事務(wù)中所有寫(xiě)請(qǐng)求的分區(qū)鍵值必須與創(chuàng)建局部事務(wù)時(shí)的分區(qū)鍵值相同,讀請(qǐng)求則無(wú)此限制。
一個(gè)局部事務(wù)同時(shí)只能用于一個(gè)請(qǐng)求中,在使用局部事務(wù)期間,其他使用此局部事務(wù)ID的操作均會(huì)失敗。
每個(gè)局部事務(wù)中兩次讀寫(xiě)操作的最大間隔為60秒。
如果超過(guò)60秒未操作局部事務(wù),則表格存儲(chǔ)服務(wù)端會(huì)認(rèn)為此局部事務(wù)超時(shí),并將局部事務(wù)丟棄。
每個(gè)局部事務(wù)中寫(xiě)入的數(shù)據(jù)量最大為4 MB,按正常的寫(xiě)請(qǐng)求數(shù)據(jù)量計(jì)算規(guī)則累加。
如果在局部事務(wù)中寫(xiě)入了未指定版本號(hào)的Cell,則該Cell的版本號(hào)會(huì)在寫(xiě)入數(shù)據(jù)時(shí)(而非提交局部事務(wù)時(shí))由表格存儲(chǔ)服務(wù)端自動(dòng)生成,生成規(guī)則與正常寫(xiě)入一個(gè)未指定版本號(hào)的Cell相同。
如果BatchWriteRow請(qǐng)求中帶有局部事務(wù)ID,則此請(qǐng)求中所有行只能操作該局部事務(wù)ID對(duì)應(yīng)的表。
在使用局部事務(wù)期間,對(duì)應(yīng)分區(qū)鍵值的數(shù)據(jù)會(huì)被加上寫(xiě)鎖,只有持有局部事務(wù)ID在局部事務(wù)范圍內(nèi)的寫(xiě)請(qǐng)求才會(huì)成功。其他非事務(wù)請(qǐng)求或持有其他局部事務(wù)ID在局部事務(wù)范圍內(nèi)的寫(xiě)請(qǐng)求均會(huì)失敗。在局部事務(wù)提交、丟棄或超時(shí)后,對(duì)應(yīng)的鎖也會(huì)被釋放。
帶有局部事務(wù)ID的讀寫(xiě)請(qǐng)求失敗不會(huì)影響局部事務(wù)本身的存活情況,您可以指定重試規(guī)則進(jìn)行重試或者主動(dòng)丟棄當(dāng)前局部事務(wù)。
參數(shù)
參數(shù) | 是否必選 | 說(shuō)明 |
TableName | 是 | 數(shù)據(jù)表名稱。 |
PrimaryKey | 是 | 數(shù)據(jù)表主鍵。
|
TransactionId | 是 | 局部事務(wù)ID,用于唯一標(biāo)識(shí)一個(gè)局部事務(wù)。 創(chuàng)建局部事務(wù)后,操作局部事務(wù)時(shí)均需要帶上局部事務(wù)ID。 |
示例
使用局部事務(wù)寫(xiě)入一行數(shù)據(jù)
以下示例用于為表的指定分區(qū)鍵創(chuàng)建一個(gè)局部事務(wù)后,在局部事務(wù)內(nèi)寫(xiě)入一行數(shù)據(jù)。如果數(shù)據(jù)寫(xiě)入成功,則提交事務(wù);如果數(shù)據(jù)寫(xiě)入失敗,則丟棄事務(wù)。
func transactionPutRow(client *tablestore.TableStoreClient, tableName string) {
//局部事務(wù)需要指定一個(gè)分區(qū)鍵(第一列主鍵)。
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
}
//獲取局部事務(wù)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)
//設(shè)置局部事務(wù)ID,局部事務(wù)ID可以通過(guò)StartLocalTransactionResponse.TransactionId獲取。
putRowChange.TransactionId = transId
putRowRequest := &tablestore.PutRowRequest{
PutRowChange: putRowChange,
}
_, err = client.PutRow(putRowRequest)
if err != nil {
//如果數(shù)據(jù)寫(xiě)入失敗,則丟棄事務(wù),局部事務(wù)中的所有數(shù)據(jù)修改均不會(huì)應(yīng)用到原有數(shù)據(jù)。
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 {
//如果數(shù)據(jù)寫(xiě)入成功,則提交事務(wù),使局部事務(wù)中的所有數(shù)據(jù)修改生效。您也可以通過(guò)丟棄事務(wù)來(lái)使數(shù)據(jù)寫(xiě)入不生效。
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)
}
}
}
使用局部事務(wù)讀取一行數(shù)據(jù)
以下示例用于為表的指定分區(qū)鍵創(chuàng)建一個(gè)局部事務(wù)后,在局部事務(wù)內(nèi)讀取一行數(shù)據(jù)。
func transactionGetRow(client *tablestore.TableStoreClient, tableName string) {
//局部事務(wù)需要指定一個(gè)分區(qū)鍵(第一列主鍵)。
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
}
//獲取局部事務(wù)ID。
transId := response.TransactionId
//讀取數(shù)據(jù)。
getRowPk := new(tablestore.PrimaryKey)
getRowPk.AddPrimaryKeyColumn("pk1", "pk1value")
getRowPk.AddPrimaryKeyColumn("pk2", int64(18))
criteria := &tablestore.SingleRowQueryCriteria{
PrimaryKey: getRowPk,
TableName: tableName,
//設(shè)置讀取最新版本的數(shù)據(jù)。
MaxVersion: 1,
//設(shè)置局部事務(wù)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)
}
//提交或丟棄局部事務(wù)。對(duì)于讀操作來(lái)說(shuō),提交局部事務(wù)或丟棄局部事務(wù)的操作是等同的。
//提交局部事務(wù),使局部事務(wù)中的所有數(shù)據(jù)修改生效。
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)
}
//丟棄局部事務(wù),局部事務(wù)中的所有數(shù)據(jù)修改均不會(huì)應(yīng)用到原有數(shù)據(jù)。
//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)
//}
}
相關(guān)文檔
如果要在局部事務(wù)內(nèi)進(jìn)行批量寫(xiě)入、范圍讀取等操作,請(qǐng)?jiān)趧?chuàng)建局部事務(wù)后,使用寫(xiě)入數(shù)據(jù)或者讀取數(shù)據(jù)文檔中的相應(yīng)操作示例以及在請(qǐng)求中帶上局部事務(wù)ID實(shí)現(xiàn)。