<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對(duì)于客戶端來說舌剂,是不透明的攻晒,你只需要知道當(dāng)內(nèi)容和元數(shù)據(jù)改變的時(shí)候cas值會(huì)改變铸抑。
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(自動(dòng)的) optimistic locking support, all you need to do is add a @Version
annotation on a long field like this:
別的數(shù)據(jù)庫遏暴,會(huì)使用一個(gè)任意的版本號(hào)和一個(gè)遞增的計(jì)數(shù)器來實(shí)現(xiàn)樂觀鎖侄刽。但是couchbase使用了更加優(yōu)良的方法,并且更容易實(shí)現(xiàn)朋凉。在一個(gè)long類型的字段上加上<code>@Version</code>注解州丹,可以自動(dòng)實(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è)文檔杂彭,會(huì)自動(dòng)把cas的值賦給<code>veriosn</code>字段墓毒。你不能去訪問這個(gè)字段,或者自己去修改它亲怠。保存一個(gè)文檔所计,要么成功要么失敗,失敗的時(shí)候团秽,會(huì)拋出<code>OptimisticLockingFailureException</code>異常主胧。當(dāng)你看到拋出這個(gè)異常,怎么處理徙垫,要看你希望應(yīng)用程序智能到什么程度讥裤。你可以重試,完成 <code>加載-更新-覆蓋</code>這個(gè)動(dòng)作 或者拋給上一層來處理姻报。
<strong>tip:悲觀鎖己英、樂觀鎖</strong>
<em>悲觀鎖</em>
是針對(duì)操作(對(duì)于某個(gè)級(jí)別的數(shù)據(jù)的)的獨(dú)占性來說的,在傳統(tǒng)的數(shù)據(jù)庫(如mysql)中吴旋,有針對(duì)庫的鎖损肛、針對(duì)表的鎖厢破、針對(duì)行記錄的鎖。悲觀鎖的缺點(diǎn)是治拿,舉個(gè)例子來說摩泪,一行記錄<code>12356346|Jon|36|Engineer</code>,如果使用了悲觀鎖劫谅,當(dāng)我做了一個(gè)<code>update user set age=26 where id=12356346</code>操作后见坑,此行數(shù)據(jù)鎖被占用,其他對(duì)此行數(shù)據(jù)的操作會(huì)被阻塞捏检。
<em>樂觀鎖</em>
樂觀鎖大多基于<code>數(shù)據(jù)版本</code>實(shí)現(xiàn)
1荞驴、讀取出數(shù)據(jù)時(shí),將此版本號(hào)一同讀出贯城,之后更新時(shí)熊楼,對(duì)此版本號(hào)加一。
2能犯、將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對(duì)應(yīng)記錄的當(dāng)前版本信息進(jìn)行比對(duì)鲫骗,如果提交的數(shù)據(jù)版本號(hào)大于數(shù)據(jù)庫表當(dāng)前版本號(hào),則予以更新踩晶,否則認(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),可以想見税弃,如果面對(duì)幾百上千個(gè)并發(fā)纪岁,這樣的情況將導(dǎo)致怎樣的后果。
樂觀鎖機(jī)制在一定程度上解決了這個(gè)問題则果。樂觀鎖幔翰,大多是基于數(shù)據(jù)版本 ( Version )記錄機(jī)制實(shí)現(xiàn)。何謂數(shù)據(jù)版本西壮?即為數(shù)據(jù)增加一個(gè)版本標(biāo)識(shí)遗增,在基于數(shù)據(jù)庫表的版本解決方案中,一般是通過為數(shù)據(jù)庫表增加一個(gè) “version” 字段來實(shí)現(xiàn)款青。
讀取出數(shù)據(jù)時(shí)做修,將此版本號(hào)一同讀出,之后更新時(shí),對(duì)此版本號(hào)加一饰及。此時(shí)蔗坯,將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對(duì)應(yīng)記錄的當(dāng)前版本信息進(jìn)行比對(duì),如果提交的數(shù)據(jù)版本號(hào)大于數(shù)據(jù)庫表當(dāng)前版本號(hào)燎含,則予以更新宾濒,否則認(rèn)為是過期數(shù)據(jù)。
對(duì)于上面修改用戶帳戶信息的例子而言屏箍,假設(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ù)版本號(hào)加一( version=2 ),連同帳戶扣除后余額( balance=$50 )祈噪,提交至數(shù)據(jù)庫更新泽铛,此時(shí)由于提交數(shù)據(jù)版本大于數(shù)據(jù)庫記錄當(dāng)前版本,數(shù)據(jù)被更新辑鲤,數(shù)據(jù)庫記錄 version 更新為 2 盔腔。
4 操作員 B 完成了操作,也將版本號(hào)加一( version=2 )試圖向數(shù)據(jù)庫提交數(shù)據(jù)( balance=$80 )月褥,但此時(shí)比對(duì)數(shù)據(jù)庫記錄版本時(shí)發(fā)現(xiàn)弛随,操作員 B 提交的數(shù)據(jù)版本號(hào)為 2 ,數(shù)據(jù)庫記錄當(dāng)前版本也為 2 宁赤,不滿足 “ 提交版本必須大于記錄當(dāng)前版本才能執(zhí)行更新 “ 的樂觀鎖策略舀透,因此,操作員 B 的提交被駁回决左。
這樣愕够,就避免了操作員 B 用基于 version=1 的舊數(shù)據(jù)修改的結(jié)果覆蓋操作員A 的操作結(jié)果的可能。