Mysql并發(fā)方案

我們?cè)诠ぷ髦杏幸豁?xiàng)業(yè)務(wù),如果A修改了,那么B就要進(jìn)行更新,如果A有多個(gè)呢?B就會(huì)有很多更新語(yǔ)句,比如當(dāng)前用戶money=10,有很多個(gè)請(qǐng)求都來更新用戶money +10,這樣怎么辦呢?

mysql的事務(wù)隔離等級(jí)

事務(wù) 事務(wù)說明 臟讀 不可重讀 幻讀
READ_UNCOMMITTED 讀取未提交內(nèi)容
READ_COMMITTED 讀取提交內(nèi)容 ×
REPEATABLE_READ 可重讀 × ×
SERIALIZABLE 可串行化 × × ×

事務(wù)介紹

  • 臟讀
    臟讀又稱無(wú)效數(shù)據(jù)的讀出,是指在數(shù)據(jù)庫(kù)訪問中,事務(wù)T1將某一值修改,然后事務(wù)T2讀取該值,此后T1因?yàn)槟撤N原因撤銷對(duì)該值的修改,這就導(dǎo)致了T2所讀取到的數(shù)據(jù)是無(wú)效的。
    臟讀就是指當(dāng)一個(gè)事務(wù)正在訪問數(shù)據(jù),并且對(duì)數(shù)據(jù)進(jìn)行了修改,而這種修改還沒有提交到數(shù)據(jù)庫(kù)中,這時(shí),另外一個(gè)事務(wù)也訪問這個(gè)數(shù)據(jù),然后使用了這個(gè)數(shù)據(jù)。因?yàn)檫@個(gè)數(shù)據(jù)是還沒有提交的數(shù)據(jù),那么另外一個(gè)事務(wù)讀到的這個(gè)數(shù)據(jù)是臟數(shù)據(jù),依據(jù)臟數(shù)據(jù)所做的操作可能是不正確的。
  • 不可重復(fù)讀
    不可重復(fù)讀,是指在數(shù)據(jù)庫(kù)訪問中,一個(gè)事務(wù)范圍內(nèi)兩個(gè)相同的查詢卻返回了不同數(shù)據(jù)。
    這是由于查詢時(shí)系統(tǒng)中其他事務(wù)修改的提交而引起的。比如事務(wù)T1讀取某一數(shù)據(jù),事務(wù)T2讀取并修改了該數(shù)據(jù),T1為了對(duì)讀取值進(jìn)行檢驗(yàn)而再次讀取該數(shù)據(jù),便得到了不同的結(jié)果。
  • 幻讀
    簡(jiǎn)單的說,幻讀指當(dāng)用戶讀取某一范圍的數(shù)據(jù)行時(shí),另一個(gè)事務(wù)又在該范圍內(nèi)插入了新行,當(dāng)用戶再讀取該范圍的數(shù)據(jù)行時(shí),會(huì)發(fā)現(xiàn)有新的“幻影” 行

選型與實(shí)驗(yàn).

我們的場(chǎng)景需要保障最終的數(shù)據(jù)的正確性, 兩個(gè)事務(wù)都開啟之后,必須保障修改數(shù)據(jù)之后提交能夠正確,這里我們選擇READ_COMMITTED允許不可重讀,或者REPEATABLE_READ 允許幻讀.

并發(fā)測(cè)試

我們使用java進(jìn)行 一個(gè)用戶的查詢和更新操作,使用的是JPA,采用并發(fā)10,每次加10進(jìn)行測(cè)試. 選取的級(jí)別是可重讀. 在并發(fā)狀態(tài)下 數(shù)據(jù)為40,很明顯無(wú)法保障數(shù)據(jù)的正確性.
并發(fā)會(huì)帶來意想不到的狀況,如何解決并發(fā)帶來的問題!!!!
我們的業(yè)務(wù)場(chǎng)景無(wú)法避免并發(fā)問題,mysql提供了鎖的機(jī)制,鑒于我們一般使用jpa,這里,我們通過JPA來檢驗(yàn)下鎖的機(jī)制.

  • 樂觀鎖
    假設(shè)有個(gè)業(yè)務(wù)他們之間一般不會(huì)造成并發(fā),假如并發(fā)了就回滾.
  • 悲觀鎖
    假設(shè)業(yè)務(wù)之間存在并發(fā)沖突.請(qǐng)求會(huì)鎖定,使用后會(huì)解鎖.
  • 鎖類型(LockMode),由于我們使用的是mysql,一般我們使用悲觀排它鎖解決并發(fā)問題. PESSIMISTIC_WRITE

tips: 我們?cè)谑褂弥幸?/p>

  • 關(guān)閉mysql自動(dòng)提交功能
  • innodb_lock_wait_timeout 超時(shí)時(shí)間設(shè)置為300'\
  • show status like ‘table%’; 查看 Table_locks_waited
  • show status like 'innodb_row_lock%';
  • 解鎖: show processlist; 找到進(jìn)程 kill id; (或者UNLOCK tables)
  • LOCK TABLES tbl_name READ; 鎖表操作.
    該業(yè)務(wù)場(chǎng)景我們要讀取B用戶,然后修改B用戶,我們?cè)谧x取用戶B時(shí)候加上鎖,這個(gè)時(shí)候所有外部的訪問將要等待處理完成之后才能夠獲取B用戶信息.
public interface UserRepository extends CrudRepository<User, Long> {
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    User findOne(Long id);
}

w

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

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

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