如一個金融系統(tǒng),當某個操作員讀取用戶的數(shù)據(jù),并在讀出的用戶數(shù)據(jù)的基礎(chǔ)上進行修改時(如更改用戶帳戶余額),如果采用悲觀鎖機制,也就意味著整個操作過 程中(從操作員讀出數(shù)據(jù)、開始修改直至提交修改結(jié)果的全過程,甚至還包括操作 員中途去煮咖啡的時間),數(shù)據(jù)庫記錄始終處于加鎖狀態(tài),可以想見,如果面對幾百上千個并發(fā),這樣的情況將導致怎樣的后果。
專注于為中小企業(yè)提供網(wǎng)站建設(shè)、網(wǎng)站設(shè)計服務(wù),電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)奉新免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了近千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。
樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基于數(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é)果的可能。
你說的這個version是mysql底層的鎖機制提供的,并不是java提供的。
使用數(shù)據(jù)版本(Version)記錄機制實現(xiàn),這是mysql樂觀鎖最常用的一種實現(xiàn)方式。所謂的數(shù)據(jù)版本就是給數(shù)據(jù)增加一個版本標識,一般是通過為數(shù)據(jù)庫表增加一個數(shù)字類型的 “version” 字段來實現(xiàn)。當讀取數(shù)據(jù)時,將version字段的值一同讀出,數(shù)據(jù)每更新一次,對此version值加1。當我們提交更新的時候,判斷數(shù)據(jù)庫表對應(yīng)記錄的當前版本信息與第一次取出來的version值進行比對,如果數(shù)據(jù)庫表當前版本號與第一次取出來的version值相等,則予以更新,否則認為是過期數(shù)據(jù),版本號重新讀取再做更新。
樂觀鎖和悲觀鎖的區(qū)別如下:
1、悲觀鎖是當線程拿到資源時,就對資源上鎖,并在提交后,才釋放鎖資源,其他線程才能使用資源。
2、樂觀鎖是當線程拿到資源時,上樂觀鎖,在提交之前,其他的鎖也可以操作這個資源,當有沖突的時候,并發(fā)機制會保留前一個提交,打回后一個提交,讓后一個線程重新獲取資源后,再操作,然后提交。和git上傳代碼一樣,兩個線程都不是直接獲取資源本身,而是先獲取資源的兩個copy版本,然后在這兩個copy版本上修改。
3、悲觀鎖和樂觀鎖在并發(fā)量低的時候,性能差不多,但是在并發(fā)量高的時候,樂觀鎖的性能遠遠優(yōu)于悲觀鎖。
4、常用的synchronized是悲觀鎖,lock是樂觀鎖。