電商平臺高并發(fā)思考-數(shù)據(jù)庫鎖和事務(wù)(2)

大部分電商業(yè)務(wù)使用的是事務(wù)性數(shù)據(jù)庫,我們本文以mysql作為分析對象,數(shù)據(jù)庫引擎為innodb,并結(jié)合常用spring框架結(jié)合起來分析數(shù)據(jù)庫鎖和事務(wù)在具體場景下怎樣發(fā)揮作用。本文從以下幾個方面講述數(shù)據(jù)庫鎖和事務(wù)。

1、數(shù)據(jù)庫鎖定義和類型

首先簡要介紹一下什么是鎖,目前才多進程多線程執(zhí)行都會存在并發(fā)問題,簡單的說就是多個操作按照隨意順序進行進行相關(guān)處理,如果不加鎖就會出現(xiàn)數(shù)據(jù)覆蓋數(shù)據(jù)計算錯誤等問題,因此為了讓操作有序進行需要加鎖,例如java中l(wèi)ock,sychronized。數(shù)據(jù)庫實現(xiàn)中為了防止并發(fā)問題使用了鎖,但是對于數(shù)據(jù)庫使用者來說我們關(guān)注的是什么情況下數(shù)據(jù)庫會加鎖,加了什么鎖。

相對其他數(shù)據(jù)庫而言,MySQL的鎖機制比較簡單,其最 顯著的特點是不同的存儲引擎支持不同的鎖機制。比如,MyISAM和MEMORY存儲引擎采用的是表級鎖(table-level locking);InnoDB存儲引擎既支持行級鎖(row-level locking),也支持表級鎖,但默認情況下是采用行級鎖。表級鎖開銷小,加鎖快;不會出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。行級鎖開銷大,加鎖慢;會出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。?

(1) MyISAM在執(zhí)行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執(zhí)行更新操作 (UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖,這個過程并不需要用戶干預(yù)

(2) InnoDB實現(xiàn)了以下兩種類型的行鎖。

共享鎖(s):又稱讀鎖。允許一個事務(wù)去讀一行,阻止其他事務(wù)獲得相同數(shù)據(jù)集的排他鎖。若事務(wù)T對數(shù)據(jù)對象A加上S鎖,則事務(wù)T可以讀A但不能修改A,其他事務(wù)只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務(wù)可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。

排他鎖(X):又稱寫鎖。允許獲取排他鎖的事務(wù)更新數(shù)據(jù),阻止其他事務(wù)取得相同的數(shù)據(jù)集共享讀鎖和排他寫鎖。若事務(wù)T對數(shù)據(jù)對象A加上X鎖,事務(wù)T可以讀A也可以修改A,其他事務(wù)不能再對A加任何鎖,直到T釋放A上的鎖。

對于共享鎖大家可能很好理解,就是多個事務(wù)只能讀數(shù)據(jù)不能改數(shù)據(jù)。?

對于排他鎖大家的理解可能就有些差別,我當初就犯了一個錯誤,以為排他鎖鎖住一行數(shù)據(jù)后,其他事務(wù)就不能讀取和修改該行數(shù)據(jù),其實不是這樣的。排他鎖指的是一個事務(wù)在一行數(shù)據(jù)加上排他鎖后,其他事務(wù)不能再在其上加其他的鎖。mysql InnoDB引擎默認的修改數(shù)據(jù)語句:update,delete,insert都會自動給涉及到的數(shù)據(jù)加上排他鎖,select語句默認不會加任何鎖類型,如果加排他鎖可以使用select …for update語句,加共享鎖可以使用select … lock in share mode語句。所以加過排他鎖的數(shù)據(jù)行在其他事務(wù)種是不能修改數(shù)據(jù)的,也不能通過for update和lock in share mode鎖的方式查詢數(shù)據(jù),但可以直接通過select …from…查詢數(shù)據(jù),因為普通查詢沒有任何鎖機制。

另外innodb引擎還有意向鎖參見mysql數(shù)據(jù)庫意向鎖意義 - 簡書

2、數(shù)據(jù)庫鎖和隔離級別

數(shù)據(jù)庫中在并發(fā)情況下數(shù)據(jù)發(fā)生異常情況主要分為以下幾類:

a、臟讀:事務(wù)A讀取了事務(wù)B更新的數(shù)據(jù),然后B回滾操作,那么A讀取到的數(shù)據(jù)是臟數(shù)據(jù)

b、不可重復(fù)讀:事務(wù) A 多次讀取同一數(shù)據(jù),事務(wù) B 在事務(wù)A多次讀取的過程中,對數(shù)據(jù)作了更新并提交,導(dǎo)致事務(wù)A多次讀取同一數(shù)據(jù)時,結(jié)果 不一致。

c、幻讀:系統(tǒng)管理員A將數(shù)據(jù)庫中所有學(xué)生的成績從具體分數(shù)改為ABCDE等級,但是系統(tǒng)管理員B就在這個時候插入了一條具體分數(shù)的記錄,當系統(tǒng)管理員A改結(jié)束后發(fā)現(xiàn)還有一條記錄沒有改過來,就好像發(fā)生了幻覺一樣,這就叫幻讀。

? ? ? ?說完了數(shù)據(jù)庫異常我們就來說下為了解決這些數(shù)據(jù)庫異常提出四種數(shù)據(jù)庫隔離級別,分別是讀未提交(read-uncommitted),不可重復(fù)讀(read-committed),可重復(fù)讀(repeatable-read),串行化(serializable)

? ? ? ?每種隔離級別都是通過加鎖的方式來保證數(shù)據(jù)庫數(shù)據(jù)一致性。另外innodb為了提交數(shù)據(jù)庫并發(fā)性結(jié)合mvcc(多版本快照,加版本號區(qū)別)和鎖結(jié)合方式,讀采用多版本不加鎖,其他都是加鎖防止發(fā)生數(shù)據(jù)異常

3、數(shù)據(jù)庫事務(wù)和鎖關(guān)系

什么是數(shù)據(jù)庫事務(wù)簡單的說來,事務(wù)指邏輯上的一組操作,組成這組操作的各個單元,要不全部成功,要不全部不成功。?

例如:A向B轉(zhuǎn)賬100元,對應(yīng)于如下兩條sql語句:

updatefromaccountsetmoney=money+100wherename='b';

updatefromaccountsetmoney=money-100wherename='a';

數(shù)據(jù)庫默認事務(wù)是自動提交的,也就是發(fā)一條sql它就執(zhí)行一條,如果想多條sql放在一個事務(wù)中執(zhí)行,則需要使用如下語句:

數(shù)據(jù)庫開啟事務(wù)命令:

start transaction?:開啟事務(wù)

rollback:回滾事務(wù)

commit:提交事務(wù)

? ? ? ? ?下面我們來說一下數(shù)據(jù)庫鎖和事務(wù)關(guān)系,數(shù)據(jù)庫在事務(wù)開始時申請數(shù)據(jù)庫鎖,例如update操作,但是事務(wù)在未提交時候獲取的鎖不釋放,如果該update是鎖定表或者制定行則其他操作該表或者改行數(shù)據(jù)操作就需要等待鎖釋放,如果其他事務(wù)不提交數(shù)據(jù)則其他等待鎖的操作等到直到超時,因此數(shù)據(jù)庫事務(wù)操作范圍不可過大,導(dǎo)致阻塞其他事務(wù)處理數(shù)據(jù)。

4、電商平臺中數(shù)據(jù)庫事務(wù)怎么處理并發(fā)

電商平臺肯定會設(shè)計到事務(wù)數(shù)據(jù)庫的操作,并且數(shù)據(jù)庫的操作可能還會引起重復(fù)操作和并發(fā)問題,在使用過程中涉及到多個表操作一定要加事務(wù),另外事務(wù)加范圍不可太大盡量最小范圍,另外利用事務(wù)的傳播機制來限制事務(wù)的是否回滾以及范圍,另外需要并發(fā)操作的可以考慮cas樂觀鎖或者條件限制進行并發(fā)操作具體一些可以參考:電商平臺高并發(fā)思考-冪等性(1)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容