云原生集成開發(fā)環(huán)境——TitanIDE
通過網(wǎng)頁在任何地方更安全、更高效地編碼2023-06-27
891
數(shù)據(jù)庫死鎖對(duì)業(yè)務(wù)來說是一個(gè)非常嚴(yán)重的問題,它一定一定一定是代碼的執(zhí)行流程處理不當(dāng)造成的。
但是重構(gòu)龐大的業(yè)務(wù)代碼不是說了就能輕易做到的事情,下面給出了一些方案,由淺入深,告訴大家解決死鎖問題的正確之道。
死鎖問題產(chǎn)生的原因和條件
死鎖問題一般發(fā)生在短時(shí)間內(nèi)多個(gè)并發(fā)任務(wù)對(duì)同一組表進(jìn)行修改的場(chǎng)景。
數(shù)據(jù)庫在更新數(shù)據(jù)時(shí)會(huì)加鎖,以確保不會(huì)發(fā)生并發(fā)寫數(shù)據(jù)。
MySQL 加鎖的機(jī)制是根據(jù)索引情況加鎖,可能是行鎖,也有可能是間隔鎖(詳情可查看文檔:https://dev.mysql.com/doc/refman/8.0/en/innodb-locks-set.html)
并發(fā)修改表A時(shí),只有一個(gè)請(qǐng)求能夠獲取到鎖,其余的請(qǐng)求需要等待它處理完成釋放鎖,才能進(jìn)行下一輪競(jìng)爭(zhēng)。
如果此時(shí)獲取到表A鎖的線程T1同時(shí)需要修改表B,但表B的鎖被線程T2獲取,且T2正在等待表A的鎖,這就造成了兩個(gè)線程相互等待,進(jìn)而死鎖。
解決辦法
1、給表增加索引
MySQL給表加鎖時(shí),鎖的范圍受索引影響。如果更新表時(shí),where條件恰好有索引覆蓋,那么MySQL可以精確地對(duì)滿足條件的行記錄加鎖,而不會(huì)對(duì)一組范圍內(nèi)的數(shù)據(jù)(甚至是全表)加鎖。
給需要更新的表添加索引,覆蓋where條件里的字段,能夠一定程度上緩解鎖的碰撞概率,降低死鎖發(fā)生次數(shù)。
2、使用主鍵更新表
這個(gè)辦法與辦法1的原理是相同的,也是利用索引讓數(shù)據(jù)庫精確地加鎖。因?yàn)橹麈I天然就是一個(gè)索引,所以不需要給表添加額外的索引。
3、縮短事務(wù)時(shí)長(zhǎng)或取消事務(wù)
許多數(shù)據(jù)庫框架或庫都會(huì)提供事務(wù)管理機(jī)制,在默認(rèn)情況下,它們采用AOP的方式來切入事務(wù)管理行為。
但是,這種事務(wù)管理行為是很粗糙的,并且會(huì)帶來一個(gè)問題:如果方法執(zhí)行的時(shí)間相當(dāng)長(zhǎng),那么這個(gè)事務(wù)也會(huì)持續(xù)相當(dāng)長(zhǎng)的時(shí)間。事務(wù)越長(zhǎng)也就意味著鎖的碰撞概率越大。
如果開發(fā)人員對(duì)框架和庫足夠熟悉,并且對(duì)數(shù)據(jù)庫事務(wù)有良好的理解,可以考慮手動(dòng)控制事務(wù),并采用編程式的事務(wù)管理方法,讓應(yīng)用程序在需要訪問數(shù)據(jù)庫的時(shí)候才開啟事務(wù)。
或者,如果系統(tǒng)不強(qiáng)調(diào)瞬態(tài)一致性,也沒有并發(fā)訪問數(shù)據(jù)沖突,那么可以完全取消事務(wù)。
4、使用合理的編程范式
123方法只能緩解數(shù)據(jù)庫表鎖的碰撞概率,但不是解決死鎖問題的根本之道。
死鎖問題更深層次的原因是:應(yīng)用程序無序地訪問數(shù)據(jù)庫,流程管控不合理。
一個(gè)清晰又整潔的編程范式,即可以有效提高代碼的可讀性,又可以降低數(shù)據(jù)庫(以及外部服務(wù))的訪問次數(shù),達(dá)到較高的程序效能。
//1.收集數(shù)據(jù)
var requiredData = queryFromDatabase()
//2.處理數(shù)據(jù)
process(requiredData)
//3.持久化處理后的數(shù)據(jù)
saveToDatabase(requiredData)
另外,盡量不要在循環(huán)里訪問內(nèi)數(shù)據(jù)庫,在循環(huán)開始前收集所有必要的信息,在循環(huán)結(jié)束后統(tǒng)一持久化到數(shù)據(jù)庫。
5、使用緩存處理熱度數(shù)據(jù)
RMDB處理密集小事務(wù)的能力并不弱,但是如果并發(fā)處理的數(shù)據(jù)有重合,就會(huì)存在死鎖的隱患。如果要解決RMDB在這方面的問題,就要投入不少精力,優(yōu)化代碼流程,精細(xì)化控制事務(wù)。
如果使用緩存來處理熱度數(shù)據(jù),可以巧妙地避開RMDB在這方面的缺陷。
緩存可以使用本地緩存,也可以使用分布式緩存,由系統(tǒng)的設(shè)計(jì)和架構(gòu)決定。
6、其他方法
除了上面的5種方法,解決事務(wù)死鎖問題的辦法還有很多,例如:其他高級(jí)編程模型、特定的中間件支持,可以開放性思考。但是再多的優(yōu)化技巧,也不如設(shè)計(jì)一個(gè)高效的程序結(jié)構(gòu)
更多云原生干貨文章,請(qǐng)點(diǎn)擊查閱>>