couchbase 樂觀鎖的實(shí)現(xiàn) spring-data-couchbase > 4.3. Optimistic Locking

<a >點(diǎn)擊查看原文</a>

Couchbase Server does not support multi-document transactions or rollback. To implement optimistic locking, Couchbase uses a CAS (compare and swap) approach. When a document is mutated, the CAS value also changes. The CAS is opaque to the client, the only thing you need to know is that it changes when the content or a meta information changes too.

Couchbase服務(wù)不支持多文檔事務(wù)或者回滾。為了實(shí)現(xiàn)樂觀鎖,couchbase使用了cas(比較并交換)的方法。當(dāng)文檔發(fā)生變化,cas值也改變。cas對于客戶端來說,是不透明的,你只需要知道當(dāng)內(nèi)容和元數(shù)據(jù)改變的時(shí)候cas值會改變。

In other datastores, similar behavior can be achieved through an arbitrary(任意的) version field with a incrementing(遞增) counter. Since Couchbase supports this in a much better fashion, it is easy to implement. If you want automatic(自動的) optimistic locking support, all you need to do is add a @Version
annotation on a long field like this:

別的數(shù)據(jù)庫,會使用一個(gè)任意的版本號和一個(gè)遞增的計(jì)數(shù)器來實(shí)現(xiàn)樂觀鎖。但是couchbase使用了更加優(yōu)良的方法,并且更容易實(shí)現(xiàn)。在一個(gè)long類型的字段上加上<code>@Version</code>注解,可以自動實(shí)現(xiàn)樂觀鎖。

<i>Example 13. A Document with optimistic locking.</i>

@Document
public class User { 
  @Version 
  private long version; 
  // constructor, getters, setters...
}

If you load a document through the template or repository, the version field will be automatically populated(填充) with the current CAS value. It is important to note that you shouldn’t access the field or even change it on your own. Once you save the document back, it will either succeed or fail with a OptimisticLockingFailureException
. If you get such an exception, the further approach(方法) depends on what you want to achieve(實(shí)現(xiàn)) application wise. You should either retry the complete load-update-write cycle or propagate(傳播) the error to the upper layers for proper(適當(dāng)?shù)模?handling.

如果你通過template或者repository加載一個(gè)文檔,會自動把cas的值賦給<code>veriosn</code>字段。你不能去訪問這個(gè)字段,或者自己去修改它。保存一個(gè)文檔,要么成功要么失敗,失敗的時(shí)候,會拋出<code>OptimisticLockingFailureException</code>異常。當(dāng)你看到拋出這個(gè)異常,怎么處理,要看你希望應(yīng)用程序智能到什么程度。你可以重試,完成 <code>加載-更新-覆蓋</code>這個(gè)動作 或者拋給上一層來處理。

<strong>tip:悲觀鎖、樂觀鎖</strong>
<em>悲觀鎖</em>

是針對操作(對于某個(gè)級別的數(shù)據(jù)的)的獨(dú)占性來說的,在傳統(tǒng)的數(shù)據(jù)庫(如mysql)中,有針對庫的鎖、針對表的鎖、針對行記錄的鎖。悲觀鎖的缺點(diǎn)是,舉個(gè)例子來說,一行記錄<code>12356346|Jon|36|Engineer</code>,如果使用了悲觀鎖,當(dāng)我做了一個(gè)<code>update user set age=26 where id=12356346</code>操作后,此行數(shù)據(jù)鎖被占用,其他對此行數(shù)據(jù)的操作會被阻塞。

<em>樂觀鎖</em>

樂觀鎖大多基于<code>數(shù)據(jù)版本</code>實(shí)現(xiàn)

1、讀取出數(shù)據(jù)時(shí),將此版本號一同讀出,之后更新時(shí),對此版本號加一。
2、將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息進(jìn)行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫表當(dāng)前版本號,則予以更新,否則認(rèn)為是過期數(shù)據(jù)

<em>樂觀鎖的例子</em>

如一個(gè)金融系統(tǒng),當(dāng)某個(gè)操作員讀取用戶的數(shù)據(jù),并在讀出的用戶數(shù)據(jù)的基礎(chǔ)上進(jìn)行修改時(shí)(如更改用戶帳戶余額),如果采用悲觀鎖機(jī)制,也就意味著整個(gè)操作過 程中(從操作員讀出數(shù)據(jù)、開始修改直至提交修改結(jié)果的全過程,甚至還包括操作 員中途去煮咖啡的時(shí)間),數(shù)據(jù)庫記錄始終處于加鎖狀態(tài),可以想見,如果面對幾百上千個(gè)并發(fā),這樣的情況將導(dǎo)致怎樣的后果。
樂觀鎖機(jī)制在一定程度上解決了這個(gè)問題。樂觀鎖,大多是基于數(shù)據(jù)版本 ( Version )記錄機(jī)制實(shí)現(xiàn)。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個(gè)版本標(biāo)識,在基于數(shù)據(jù)庫表的版本解決方案中,一般是通過為數(shù)據(jù)庫表增加一個(gè) “version” 字段來實(shí)現(xiàn)。
讀取出數(shù)據(jù)時(shí),將此版本號一同讀出,之后更新時(shí),對此版本號加一。此時(shí),將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息進(jìn)行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫表當(dāng)前版本號,則予以更新,否則認(rèn)為是過期數(shù)據(jù)。
對于上面修改用戶帳戶信息的例子而言,假設(shè)數(shù)據(jù)庫中帳戶信息表中有一個(gè) version 字段,當(dāng)前值為 1 ;而當(dāng)前帳戶余額字段( balance )為 $100 。

1 操作員 A 此時(shí)將其讀出( version=1 ),并從其帳戶余額中扣除 $50( $100-$50 )。
2 在操作員 A 操作的過程中,操作員B 也讀入此用戶信息( version=1 ),并從其帳戶余額中扣除 $20 ( $100-$20 )。
3 操作員 A 完成了修改工作,將數(shù)據(jù)版本號加一( version=2 ),連同帳戶扣除后余額( balance=$50 ),提交至數(shù)據(jù)庫更新,此時(shí)由于提交數(shù)據(jù)版本大于數(shù)據(jù)庫記錄當(dāng)前版本,數(shù)據(jù)被更新,數(shù)據(jù)庫記錄 version 更新為 2 。
4 操作員 B 完成了操作,也將版本號加一( version=2 )試圖向數(shù)據(jù)庫提交數(shù)據(jù)( balance=$80 ),但此時(shí)比對數(shù)據(jù)庫記錄版本時(shí)發(fā)現(xiàn),操作員 B 提交的數(shù)據(jù)版本號為 2 ,數(shù)據(jù)庫記錄當(dāng)前版本也為 2 ,不滿足 “ 提交版本必須大于記錄當(dāng)前版本才能執(zhí)行更新 “ 的樂觀鎖策略,因此,操作員 B 的提交被駁回。
這樣,就避免了操作員 B 用基于 version=1 的舊數(shù)據(jù)修改的結(jié)果覆蓋操作員A 的操作結(jié)果的可能。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容