數(shù)據(jù)庫(kù)中的事務(wù)與并發(fā)問題的案例講解
發(fā)表時(shí)間:2023-08-24 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]數(shù)據(jù)庫(kù)中的事務(wù)和并發(fā)問題探討引子最近有同事寫了段代碼,負(fù)責(zé)創(chuàng)建訂單的邏輯,代碼審查時(shí)發(fā)現(xiàn)可能會(huì)有并發(fā)的問題。同事并不認(rèn)同,他認(rèn)為他的邏輯是寫在存儲(chǔ)過程中的,應(yīng)該沒有問題。代碼的邏輯大概是(偽代碼):begin transactionif 查詢到客戶存在進(jìn)行中的訂單rollback transact...
數(shù)據(jù)庫(kù)中的事務(wù)和并發(fā)問題探討
引子
最近有同事寫了段代碼,負(fù)責(zé)創(chuàng)建訂單的邏輯,代碼審查時(shí)發(fā)現(xiàn)可能會(huì)有并發(fā)的問題。同事并不認(rèn)同,他認(rèn)為他的邏輯是寫在存儲(chǔ)過程中的,應(yīng)該沒有問題。
代碼的邏輯大概是(偽代碼):
begin transaction
if 查詢到客戶存在進(jìn)行中的訂單
rollback transaction
if 查詢到設(shè)備存在進(jìn)行中的訂單
rollback transaction
插入訂單
commit transaction
下面針對(duì)這個(gè)邏輯進(jìn)行分析,為什么這個(gè)事務(wù)會(huì)出現(xiàn)并發(fā)問題。
事務(wù)概述
首先,提出兩個(gè)問題,然后帶著問題討論事務(wù)相關(guān)的知識(shí)點(diǎn),最后來解決這兩個(gè)問題并回答前文的問題。
第一個(gè)問題,事務(wù)是否可以并發(fā)?
第二個(gè)問題,數(shù)據(jù)庫(kù)是怎么隔離事務(wù)的?
事務(wù)的表現(xiàn)特性
數(shù)據(jù)庫(kù)中執(zhí)行事務(wù)涉及到很多方面,包括如何處理臨界資源,如何加鎖解鎖等等。但是無論事務(wù)如何執(zhí)行,都需要保證以下幾個(gè)特性:
原子性
一致性
隔離性
持久性
原子性:所有的操作是一個(gè)邏輯單元,要么都提交成功,要么就都失;
一致性:只有合法的數(shù)據(jù)被寫入數(shù)據(jù)庫(kù),否則事務(wù)回滾到最初的狀態(tài);
隔離性:允許多個(gè)事務(wù)同時(shí)進(jìn)行,而不會(huì)破壞數(shù)據(jù)的正確性和完整性;
持久性:事務(wù)結(jié)束后,已經(jīng)提交的結(jié)果被固化保存。
數(shù)據(jù)庫(kù)的各種鎖
共享鎖
共享鎖用于非獨(dú)占的業(yè)務(wù),允許多個(gè)事務(wù)同時(shí)讀取鎖定的資源,但是不允許資源被更新。
加鎖時(shí)機(jī):執(zhí)行select語句時(shí)默認(rèn)會(huì)被加上
解鎖時(shí)機(jī):執(zhí)行完讀取后默認(rèn)解除
與其他鎖兼容性:數(shù)據(jù)上被設(shè)置了共享鎖,則不會(huì)允許再增加共享鎖和獨(dú)占鎖
并發(fā)性能:具有良好的并發(fā)性能
排他鎖
排他鎖,也叫獨(dú)占鎖。顧名思義,被排他鎖鎖定的資源不會(huì)允許其他事務(wù)進(jìn)行任何操作。
加鎖時(shí)機(jī):執(zhí)行insert,update,delete時(shí)默認(rèn)會(huì)被加上
解鎖時(shí)機(jī):事務(wù)結(jié)束才能解除
兼容性:如果數(shù)據(jù)上有其他鎖,不能增加獨(dú)占鎖;同樣獨(dú)占鎖存在時(shí)也不會(huì)允許增加其他鎖
并發(fā)性能:其他事務(wù)必須等待前一個(gè)事務(wù)結(jié)束后才能執(zhí)行,不能并發(fā),只能串行
更新鎖
在更新的初始階段用于鎖定所需要的資源,防止在讀取階段使用共享鎖造成死鎖。
加鎖時(shí)機(jī):執(zhí)行update時(shí),使用更新鎖鎖定相關(guān)資源
解鎖時(shí)機(jī):讀取完畢,執(zhí)行更新操作時(shí),更新鎖升級(jí)為獨(dú)占鎖
兼容性:更新鎖與共享鎖兼容,即可以同時(shí)存在更新鎖和共享鎖,但只能有一個(gè)更新鎖
并發(fā)性能:更新初期的讀取階段可以允許其他事務(wù)讀取資源,允許有限的并發(fā);后期對(duì)資源進(jìn)行獨(dú)占時(shí)不允許并發(fā)。
事務(wù)隔離級(jí)別
通用的事務(wù)隔離級(jí)別有四種,SQL Server還有另外擴(kuò)展出來的級(jí)別,在此不多介紹。
Serializable(串行化)
工作方式類似于可重復(fù)讀。但它不僅會(huì)鎖定受影響的數(shù)據(jù),還會(huì)鎖定這個(gè)范圍。這就阻止了新數(shù)據(jù)插入查詢所涉及的范圍,這種情況可以導(dǎo)致幻像讀。
Repeatable Read(可重復(fù)讀)
像已提交讀級(jí)別那樣讀數(shù)據(jù),但會(huì)保持共享鎖直到事務(wù)結(jié)束。
Read Commit
只讀取提交的數(shù)據(jù)并等待其他事務(wù)釋放排他鎖。讀數(shù)據(jù)的共享鎖在讀操作完成后立即釋放。已提交讀是SQL Server的默認(rèn)隔離級(jí)別。
Read Uncommited
在讀數(shù)據(jù)時(shí)不會(huì)檢查或使用任何鎖。因此,在這種隔離級(jí)別中可能讀取到?jīng)]有提交的數(shù)據(jù)。
回答前文的問題
第一個(gè)問題,事務(wù)是否可以并發(fā)?
答案是肯定的,數(shù)據(jù)庫(kù)中為了提高性能,允許同時(shí)進(jìn)行多個(gè)事務(wù)操作,這個(gè)事務(wù)跟發(fā)起方式無關(guān),使用存儲(chǔ)過程發(fā)起,或者使用代碼發(fā)起,又或者使用普通的SQL語句發(fā)起并沒有什么區(qū)別。
第二個(gè)問題,數(shù)據(jù)庫(kù)是怎么隔離事務(wù)的?
要回答這個(gè)問題,先要理解數(shù)據(jù)庫(kù)中的鎖機(jī)制和數(shù)據(jù)庫(kù)事務(wù)隔離級(jí)別。數(shù)據(jù)庫(kù)中的鎖可以分為三種類型:共享鎖、獨(dú)占鎖和更新鎖。使用不同級(jí)別的鎖并配合不同的鎖定范圍已達(dá)到不同的事務(wù)隔離級(jí)別并在此基礎(chǔ)上并發(fā)或串行執(zhí)行事務(wù)。
第三個(gè)問題,為什么本文開頭的事務(wù)會(huì)存在并發(fā)問題?
因?yàn)槭聞?wù)的開始執(zhí)行的是select,select使用的是共享鎖,有可能并發(fā)的事務(wù)在同一時(shí)間執(zhí)行select導(dǎo)致同時(shí)認(rèn)為自己都是合法操作,而排隊(duì)執(zhí)行后續(xù)的事務(wù)。結(jié)果導(dǎo)致了實(shí)際上就有可能插入重復(fù)的數(shù)據(jù),比如只剩下一個(gè)商品,卻創(chuàng)建了兩個(gè)銷售訂單。
如何防止并發(fā)問題
在事務(wù)中
根據(jù)前文所講,使用insert,update或delete可以在默認(rèn)事務(wù)級(jí)別人為造成事務(wù)串行化,因此可以在事務(wù)內(nèi)部一開始都使用update更新一條公共的數(shù)據(jù),這樣的話同類型的事務(wù)都會(huì)串行化,然后再增加一個(gè)判斷語句,用于判斷后續(xù)的事務(wù)內(nèi)容是否應(yīng)該執(zhí)行。這樣足以確保所有的操作都按照合理合法,唯一的缺點(diǎn)是可能造成性能問題。
在事務(wù)外
現(xiàn)在分布式的系統(tǒng)越來越多,但是再分布的系統(tǒng)也會(huì)有些共享資源,比如redis或zookeeper,可以利用redis或者zookeeper造一些分布式的鎖(此類屬于其他博文內(nèi)容,在此不再展開)。利用事務(wù)外部的鎖將同類型的事務(wù)做一些串行化處理,再配合事務(wù)內(nèi)部的檢查機(jī)制,足以確保解決事務(wù)的并發(fā)問題。
參考資料
事務(wù)并發(fā)的問題及處理
數(shù)據(jù)庫(kù)事務(wù)的四大特性以及事務(wù)的隔離級(jí)別
數(shù)據(jù)庫(kù)事務(wù)和并發(fā)
SQLServer事務(wù)的隔離級(jí)別
以上就是數(shù)據(jù)庫(kù)中的事務(wù)和并發(fā)問題的實(shí)例講解的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
學(xué)習(xí)教程快速掌握從入門到精通的SQL知識(shí)。