<a >點擊查看原文</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ù)或者回滾。為了實現(xiàn)樂觀鎖,couchbase使用了cas(比較并交換)的方法。當文檔發(fā)生變化,cas值也改變。cas對于客戶端來說,是不透明的,你只需要知道當內(nèi)容和元數(shù)據(jù)改變的時候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ù)庫,會使用一個任意的版本號和一個遞增的計數(shù)器來實現(xiàn)樂觀鎖。但是couchbase使用了更加優(yōu)良的方法,并且更容易實現(xiàn)。在一個long類型的字段上加上<code>@Version</code>注解,可以自動實現(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(實現(xiàn)) application wise. You should either retry the complete load-update-write cycle or propagate(傳播) the error to the upper layers for proper(適當?shù)模?handling.
如果你通過template或者repository加載一個文檔,會自動把cas的值賦給<code>veriosn</code>字段。你不能去訪問這個字段,或者自己去修改它。保存一個文檔,要么成功要么失敗,失敗的時候,會拋出<code>OptimisticLockingFailureException</code>異常。當你看到拋出這個異常,怎么處理,要看你希望應(yīng)用程序智能到什么程度。你可以重試,完成 <code>加載-更新-覆蓋</code>這個動作 或者拋給上一層來處理。
<strong>tip:悲觀鎖、樂觀鎖</strong>
<em>悲觀鎖</em>
是針對操作(對于某個級別的數(shù)據(jù)的)的獨占性來說的,在傳統(tǒng)的數(shù)據(jù)庫(如mysql)中,有針對庫的鎖、針對表的鎖、針對行記錄的鎖。悲觀鎖的缺點是,舉個例子來說,一行記錄<code>12356346|Jon|36|Engineer</code>,如果使用了悲觀鎖,當我做了一個<code>update user set age=26 where id=12356346</code>操作后,此行數(shù)據(jù)鎖被占用,其他對此行數(shù)據(jù)的操作會被阻塞。
<em>樂觀鎖</em>
樂觀鎖大多基于<code>數(shù)據(jù)版本</code>實現(xiàn)
1、讀取出數(shù)據(jù)時,將此版本號一同讀出,之后更新時,對此版本號加一。
2、將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對應(yīng)記錄的當前版本信息進行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫表當前版本號,則予以更新,否則認為是過期數(shù)據(jù)
<em>樂觀鎖的例子</em>
如一個金融系統(tǒng),當某個操作員讀取用戶的數(shù)據(jù),并在讀出的用戶數(shù)據(jù)的基礎(chǔ)上進行修改時(如更改用戶帳戶余額),如果采用悲觀鎖機制,也就意味著整個操作過 程中(從操作員讀出數(shù)據(jù)、開始修改直至提交修改結(jié)果的全過程,甚至還包括操作 員中途去煮咖啡的時間),數(shù)據(jù)庫記錄始終處于加鎖狀態(tài),可以想見,如果面對幾百上千個并發(fā),這樣的情況將導(dǎo)致怎樣的后果。
樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基于數(shù)據(jù)版本 ( Version )記錄機制實現(xiàn)。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個版本標識,在基于數(shù)據(jù)庫表的版本解決方案中,一般是通過為數(shù)據(jù)庫表增加一個 “version” 字段來實現(xiàn)。
讀取出數(shù)據(jù)時,將此版本號一同讀出,之后更新時,對此版本號加一。此時,將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對應(yīng)記錄的當前版本信息進行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫表當前版本號,則予以更新,否則認為是過期數(shù)據(jù)。
對于上面修改用戶帳戶信息的例子而言,假設(shè)數(shù)據(jù)庫中帳戶信息表中有一個 version 字段,當前值為 1 ;而當前帳戶余額字段( balance )為 $100 。
1 操作員 A 此時將其讀出( version=1 ),并從其帳戶余額中扣除 $50( $100-$50 )。
2 在操作員 A 操作的過程中,操作員B 也讀入此用戶信息( version=1 ),并從其帳戶余額中扣除 $20 ( $100-$20 )。
3 操作員 A 完成了修改工作,將數(shù)據(jù)版本號加一( version=2 ),連同帳戶扣除后余額( balance=$50 ),提交至數(shù)據(jù)庫更新,此時由于提交數(shù)據(jù)版本大于數(shù)據(jù)庫記錄當前版本,數(shù)據(jù)被更新,數(shù)據(jù)庫記錄 version 更新為 2 。
4 操作員 B 完成了操作,也將版本號加一( version=2 )試圖向數(shù)據(jù)庫提交數(shù)據(jù)( balance=$80 ),但此時比對數(shù)據(jù)庫記錄版本時發(fā)現(xiàn),操作員 B 提交的數(shù)據(jù)版本號為 2 ,數(shù)據(jù)庫記錄當前版本也為 2 ,不滿足 “ 提交版本必須大于記錄當前版本才能執(zhí)行更新 “ 的樂觀鎖策略,因此,操作員 B 的提交被駁回。
這樣,就避免了操作員 B 用基于 version=1 的舊數(shù)據(jù)修改的結(jié)果覆蓋操作員A 的操作結(jié)果的可能。