事務(wù)

事務(wù)的作用是保證一系列操作的原子性。
原子性是指這一系列操作,要么全部執(zhí)行,要么全部不執(zhí)行。

最終目的是保證數(shù)據(jù)的一致性。

舉個(gè)例子:用戶積分贈(zèng)送,用戶A向用戶B贈(zèng)送1000積分。這個(gè)贈(zèng)送功能是由一系列操作組成的(實(shí)際只有兩個(gè),用戶A積分-1000,用戶B積分+1000)。

如果用戶A積分-1000成功,而用戶B積分+1000的時(shí)候出現(xiàn)異常了,會(huì)出現(xiàn)1000積分莫名蒸發(fā)了。

如果有事務(wù),在用戶B積分+1000的時(shí)候出現(xiàn)異常,沒有完成的時(shí)候,會(huì)回滾用戶A積分-1000操作,整體上看就像沒有進(jìn)行過積分贈(zèng)送一樣,不會(huì)有積分蒸發(fā)。

常見的有數(shù)據(jù)庫事務(wù)、分布式事務(wù)。

數(shù)據(jù)庫事務(wù)

數(shù)據(jù)庫事務(wù)是由數(shù)據(jù)庫服務(wù)器消耗大量系統(tǒng)資源提供的特性,因此使用數(shù)據(jù)庫事務(wù)有幾個(gè)原則:

  • 能不用則不用,對數(shù)據(jù)一致性要求不高的場景可以考慮不使用事務(wù)。
  • 保證事務(wù)盡可能小。把一些無關(guān)的數(shù)據(jù)處理和查詢操作提取到事務(wù)外。

隔離級(jí)別

主要是描述了多個(gè)并發(fā)事務(wù)之間的行為。

常見并發(fā)問題 描述
丟失更新 撤銷一個(gè)事務(wù)時(shí),把其他事務(wù)已提交的更新數(shù)據(jù)覆蓋(A和B事務(wù)并發(fā)執(zhí)行,A事務(wù)執(zhí)行更新后,提交;B事務(wù)在A事務(wù)更新后,B事務(wù)結(jié)束前也做了對該行數(shù)據(jù)的更新操作,然后回滾,則兩次更新操作都丟失了)
臟讀 一個(gè)事務(wù)讀到另一個(gè)事務(wù)未提交的更新數(shù)據(jù)(A和B事務(wù)并發(fā)執(zhí)行,B事務(wù)執(zhí)行更新后,A事務(wù)查詢B事務(wù)沒有提交的數(shù)據(jù),B事務(wù)回滾,則A事務(wù)得到的數(shù)據(jù)不是數(shù)據(jù)庫中的真實(shí)數(shù)據(jù)。也就是臟數(shù)據(jù),即和數(shù)據(jù)庫中不一致的數(shù)據(jù))
不可重復(fù)讀 一個(gè)事務(wù)讀到另一個(gè)事務(wù)已提交的更新數(shù)據(jù)(A和B事務(wù)并發(fā)執(zhí)行,A事務(wù)查詢數(shù)據(jù),然后B事務(wù)更新該數(shù)據(jù),A再次查詢該數(shù)據(jù)時(shí),發(fā)現(xiàn)該數(shù)據(jù)變化了)
覆蓋更新 這是不可重復(fù)讀中的特例,一個(gè)事務(wù)覆蓋另一個(gè)事務(wù)已提交的更新數(shù)據(jù)(即A事務(wù)更新數(shù)據(jù),然后B事務(wù)更新該數(shù)據(jù),A事務(wù)查詢發(fā)現(xiàn)自己更新的數(shù)據(jù)變了)
幻讀 一個(gè)事務(wù)讀到另一個(gè)事務(wù)已提交的新插入的數(shù)據(jù)(A和B事務(wù)并發(fā)執(zhí)行,A事務(wù)查詢數(shù)據(jù),B事務(wù)插入或者刪除數(shù)據(jù),A事務(wù)再次查詢發(fā)現(xiàn)結(jié)果集中有以前沒有的數(shù)據(jù)或者以前有的數(shù)據(jù)消失了)

MYSQL提供了以下幾種隔離級(jí)別:

可以通過命令查看當(dāng)前的隔離級(jí)別:

select @@global.tx_isolation,@@tx_isolation;
隔離級(jí)別 描述 并發(fā)問題
Serializable(串行化 一個(gè)事務(wù)在執(zhí)行過程中完全看不到其他事務(wù)對數(shù)據(jù)庫所做的更新(事務(wù)執(zhí)行的時(shí)候不允許別的事務(wù)并發(fā)執(zhí)行。事務(wù)串行化執(zhí)行,事務(wù)只能一個(gè)接著一個(gè)地執(zhí)行,而不能并發(fā)執(zhí)行。
Repeatable Read(可重復(fù)讀) 一個(gè)事務(wù)在執(zhí)行過程中可以看到其他事務(wù)已經(jīng)提交的新插入的記錄,但是不能看到其他其他事務(wù)對已有記錄的更新。 幻讀
Read Commited(讀已提交數(shù)據(jù)) 一個(gè)事務(wù)在執(zhí)行過程中可以看到其他事務(wù)已經(jīng)提交的新插入的記錄,而且能看到其他事務(wù)已經(jīng)提交的對已有記錄的更新。 不可重復(fù)讀、覆蓋更新、幻讀
Read Uncommitted(讀未提交數(shù)據(jù)) 一個(gè)事務(wù)在執(zhí)行過程中可以看到其他事務(wù)沒有提交的新插入的記錄,而且能看到其他事務(wù)沒有提交的對已有記錄的更新。 丟失更新、臟讀、不可重復(fù)讀、覆蓋更新、幻讀

傳播特性

描述的是事務(wù)嵌套的行為。
spring提供了7種事務(wù)傳播特性:

傳播特性 描述
PROPAGATION_REQUIRED 如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù),如果已經(jīng)存在一個(gè)事務(wù)中,加入到這個(gè)事務(wù)中。這是最常見的選擇。
PROPAGATION_SUPPORTS 支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
PROPAGATION_MANDATORY 使用當(dāng)前的事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
PROPAGATION_REQUIRES_NEW 新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
PROPAGATION_NOT_SUPPORTED 以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
PROPAGATION_NEVER 以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
PROPAGATION_NESTED 如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則執(zhí)行與 PROPAGATION_REQUIRED 類似的操作。

Spring 注解事務(wù)使用

小例子地址:http://git.oschina.net/lan4demo/transaction-demo

小例子使用了內(nèi)存模式的h2數(shù)據(jù)庫,但是有興趣的朋友可以配置上本地的mysql,使用tcpdump進(jìn)行抓包,可以對比得出使用數(shù)據(jù)庫事務(wù)的不同之處。

分布式事務(wù)

分布式事務(wù)產(chǎn)生的原因:

  • 分庫分表
  • SOA/微服務(wù)

基于XA協(xié)議的兩階段提交

兩階段提交

有個(gè)全局的事務(wù)管理器。分析其流程,可以看出能夠?qū)崿F(xiàn)強(qiáng)一致性,缺點(diǎn)也很明顯,系統(tǒng)開銷很大,不適合并發(fā)高的網(wǎng)站,比如電商。

消息事務(wù)+最終一致性

以兩個(gè)系統(tǒng)的協(xié)作為例子,該解決方案對系統(tǒng)A和系統(tǒng)B的分布式事務(wù),其實(shí)進(jìn)行了問題轉(zhuǎn)換:

  • 分布式事務(wù)換成了系統(tǒng)A的本地事務(wù)和消息事務(wù)。是對消息中間件的一種特殊利用,它是將本地事務(wù)和發(fā)消息放在了一個(gè)分布式事務(wù)里,保證要么本地操作成功成功并且對外發(fā)消息成功,要么兩者都失敗
  • 系統(tǒng)A和系統(tǒng)B的協(xié)作通過消息隊(duì)列來完成,在系統(tǒng)A的事務(wù)提交了,消息發(fā)送出去之后,將會(huì)通過消息重投來保證最終一致性。

比如去哪兒網(wǎng)的消息隊(duì)列中間件QMQ就是通過將消息與業(yè)務(wù)數(shù)據(jù)庫放在一起實(shí)現(xiàn)的消息事務(wù)。

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

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

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