18.7.23
一朋其、概念:
作為單個邏輯工作單元執(zhí)行的一系列操作,要么完全地執(zhí)行斗遏,要么完全地不執(zhí)行山卦。
一個邏輯工作單元要成為事務(wù),必須滿足所謂的ACID(原子性、一致性账蓉、隔離性和持久性)屬性枚碗。
事務(wù)是數(shù)據(jù)庫運(yùn)行中的一個邏輯工作單位,由DBMS中的事務(wù)管理子系統(tǒng)負(fù)責(zé)事務(wù)的處理铸本。
二肮雨、ACID(原子性、一致性箱玷、隔離性和持久性)
1怨规、原子性(Atomic):對于其數(shù)據(jù)修改,要么全都執(zhí)行锡足,要么全都不執(zhí)行波丰。
如果執(zhí)行一半發(fā)生問題,則需要回滾舶得。
在多事務(wù)并發(fā)執(zhí)行中掰烟,即使沒有發(fā)生問題,也可導(dǎo)致最終結(jié)果錯誤沐批,因此還需要其他特性纫骑。
2、一致性(Consistency)
一致性是指事務(wù)必須使數(shù)據(jù)庫從一個一致性狀態(tài)變換到另一個一致性狀態(tài)九孩,也就是說一個事務(wù)執(zhí)行之前和執(zhí)行之后都必須處于一致性狀態(tài)先馆。
例子1:拿轉(zhuǎn)賬來說,假設(shè)用戶A和用戶B兩者的錢加起來一共是5000捻撑,那么不管A和B之間如何轉(zhuǎn)賬,轉(zhuǎn)幾次賬缤底,事務(wù)結(jié)束后兩個用戶的錢相加起來應(yīng)該還得是5000顾患,這就是事務(wù)的一致性。
例子2:對銀行轉(zhuǎn)帳事務(wù)个唧,不管事務(wù)成功還是失敗江解,應(yīng)該保證事務(wù)結(jié)束后ACCOUNT表中A和B的存款總額始終為2000元。如果一個人扣100元徙歼,一個人得50元犁河,就破壞了一致性。
事務(wù)的一致性決定了一個系統(tǒng)設(shè)計和實(shí)現(xiàn)的復(fù)雜度魄梯。事務(wù)可以不同程度的一致性:
·強(qiáng)一致性:讀操作可以立即讀到提交的更新操作桨螺。
·弱一致性:提交的更新操作,不一定立即會被讀操作讀到酿秸,此種情況會存在一個不一致窗口灭翔,指的是讀操作可以讀到最新值的一段時間。
·最終一致性:是弱一致性的特例辣苏。事務(wù)更新一份數(shù)據(jù)肝箱,最終一致性保證在沒有其他事務(wù)更新同樣的值的話哄褒,最終所有的事務(wù)都會讀到之前事務(wù)更新的最新值。如果沒有錯誤發(fā)生煌张,不一致窗口的大小依賴于:通信延遲呐赡,系統(tǒng)負(fù)載等。
·其他一致性變體還有:
·單調(diào)一致性:如果一個進(jìn)程已經(jīng)讀到一個值骏融,那么后續(xù)不會讀到更早的值链嘀。
·會話一致性:保證客戶端和服務(wù)器交互的會話過程中,讀操作可以讀到更新操作后的最新值绎谦。
3管闷、隔離性(Isolation)
多個事務(wù)并發(fā)訪問時,事務(wù)之間是隔離的窃肠,一個事務(wù)不應(yīng)該影響其它事務(wù)運(yùn)行效果包个。
事務(wù)并發(fā)的隔離性是可以通過隔離級別的設(shè)置來控制的。
由事務(wù)并發(fā)引起的三個問題(臟讀冤留、不可重復(fù)讀碧囊、幻讀)是可以通過隔離級別的調(diào)整來控制的。
4纤怒、持久性(Durability)
持久性糯而,意味著在事務(wù)完成以后,該事務(wù)所對數(shù)據(jù)庫所作的更改便持久的保存在數(shù)據(jù)庫之中泊窘,并不會被回滾熄驼。即使出現(xiàn)了任何事故比如斷電等,事務(wù)一旦提交烘豹,則持久化保存在數(shù)據(jù)庫中瓜贾。
三、由事務(wù)并發(fā)引起的5類問題
1携悯、第一類丟失更新(Update Lost):此種更新丟失是因?yàn)榛貪L的原因祭芦,所以也叫回滾丟失。此時兩個事務(wù)同時更新count憔鬼,兩個事務(wù)都讀取到100龟劲,事務(wù)一更新成功并提交,count=100+1=101轴或,事務(wù)二出于某種原因更新失敗了昌跌,然后回滾,事務(wù)二就把count還原為它一開始讀到的100照雁,此時事務(wù)一的更新就這樣丟失了避矢。
2、臟讀(Dirty Read):此種異常時因?yàn)橐粋€事務(wù)讀取了另一個事務(wù)修改了但是未提交的數(shù)據(jù)。舉個例子审胸,事務(wù)一更新了count=101亥宿,但是沒有提交,事務(wù)二此時讀取count砂沛,值為101而不是100烫扼,然后事務(wù)一出于某種原因回滾了,然后第二個事務(wù)讀取的這個值就是噩夢的開始碍庵。
當(dāng)事務(wù)隔離級別為read uncommitted的時候映企,一個事務(wù)執(zhí)行到一半并未提交,另一個事務(wù)讀到了數(shù)據(jù)静浴,前一個事物回滾堰氓,這樣第二個事務(wù)讀到的就是不真實(shí)的數(shù)據(jù)。
3苹享、不可重復(fù)讀(Not Repeatable Read):此種異常是一個事務(wù)對同一行數(shù)據(jù)執(zhí)行了兩次或更多次查詢双絮,但是卻得到了不同的結(jié)果,也就是在一個事務(wù)里面你不能重復(fù)(即多次)讀取一行數(shù)據(jù)得问,如果你這么做了囤攀,不能保證每次讀取的結(jié)果是一樣的,有可能一樣有可能不一樣宫纬。造成這個結(jié)果是在兩次查詢之間有別的事務(wù)對該行數(shù)據(jù)做了更新操作焚挠。舉個例子,事務(wù)一先查詢了count漓骚,值為100蝌衔,此時事務(wù)二更新了count=101,事務(wù)一再次讀取count,值就會變成101蝌蹂,兩次讀取結(jié)果不一樣噩斟。
此時他們的隔離級別都是read committed。
4叉信、第二類丟失更新(Second Update Lost):此種更新丟失是因?yàn)楦卤黄渌聞?wù)給覆蓋了亩冬,也可以叫覆蓋丟失艘希。舉個例子硼身,兩個事務(wù)同時更新count,都讀取100這個初始值覆享,事務(wù)一先更新成功并提交佳遂,count=100+1=101,事務(wù)二后更新成功并提交撒顿,count=100+1=101,由于事務(wù)二count還是從100開始增加丑罪,事務(wù)一的更新就這樣丟失了。
5、幻讀(Phantom Read):幻讀和不可重復(fù)讀有點(diǎn)像吩屹,只是針對的不是數(shù)據(jù)的值而是數(shù)據(jù)的數(shù)量跪另。此種異常是一個事務(wù)在兩次查詢的過程中數(shù)據(jù)的數(shù)量不同,讓人以為發(fā)生幻覺煤搜,幻讀大概就是這么得來的吧免绿。舉個例子,事務(wù)一查詢order表有多少條記錄擦盾,事務(wù)二新增了一條記錄嘲驾,然后事務(wù)一查了一下order表有多少記錄,發(fā)現(xiàn)和第一次不一樣迹卢,這就是幻讀辽故。
MYSQL數(shù)據(jù)庫的幻讀是有概率性的,不好演示腐碱。
四誊垢、數(shù)據(jù)庫事務(wù)隔離級別
數(shù)據(jù)庫事務(wù)隔離級別可以影響以上問題。
數(shù)據(jù)庫的隔離級別實(shí)現(xiàn)一般是通過數(shù)據(jù)庫鎖實(shí)現(xiàn)的喻杈。
1彤枢、讀未提交(Read Uncommitted):該隔離級別指即使一個事務(wù)的更新語句沒有提交,但是別的事務(wù)可以讀到這個改變,幾種異常情況都可能出現(xiàn)筒饰。極易出錯缴啡,沒有安全性可言,基本不會使用瓷们。
那么臟讀业栅、不可重復(fù)讀、幻讀都是有可能發(fā)生的
2谬晕、讀已提交(Read Committed):該隔離級別指一個事務(wù)只能看到其他事務(wù)的已經(jīng)提交的更新碘裕,看不到未提交的更新,消除了臟讀和第一類丟失更新攒钳,這是大多數(shù)數(shù)據(jù)庫的默認(rèn)隔離級別帮孔,如Oracle,Sqlserver。
可避免臟讀不撑,不能避免不可重復(fù)讀和幻讀
3文兢、可重復(fù)讀(Repeatable Read):該隔離級別指一個事務(wù)中進(jìn)行兩次或多次同樣的對于數(shù)據(jù)內(nèi)容的查詢,得到的結(jié)果是一樣的焕檬,但不保證對于數(shù)據(jù)條數(shù)的查詢是一樣的姆坚,只要存在讀改行數(shù)據(jù)就禁止寫,消除了不可重復(fù)讀和第二類更新丟失实愚,這是Mysql數(shù)據(jù)庫的默認(rèn)隔離級別兼呵。
避免臟讀兔辅、不可重復(fù)讀,但是幻讀還是有可能產(chǎn)生
4击喂、串行化(Serializable):意思是說這個事務(wù)執(zhí)行的時候不允許別的事務(wù)并發(fā)執(zhí)行.完全串行化的讀维苔,只要存在讀就禁止寫,但可以同時讀,消除了幻讀懂昂。這是事務(wù)隔離的最高級別蕉鸳,雖然最安全最省心,但是效率太低忍法,一般不會用潮尝。
避免所有異常讀的產(chǎn)生
5、他們的安全性是遞增的饿序,效率性是遞減的勉失。
五、各種隔離級別對各異常的控制能力
六原探、數(shù)據(jù)庫鎖
一般可以分為兩類乱凿,一個是悲觀鎖,一個是樂觀鎖咽弦。
悲觀鎖一般就是我們通常說的數(shù)據(jù)庫鎖機(jī)制徒蟆,樂觀鎖一般是指用戶自己實(shí)現(xiàn)的一種鎖機(jī)制,比如hibernate實(shí)現(xiàn)的樂觀鎖甚至編程語言也有樂觀鎖的思想的應(yīng)用型型。
悲觀鎖:顧名思義段审,就是很悲觀,它對于數(shù)據(jù)被外界修改持保守態(tài)度闹蒜,認(rèn)為數(shù)據(jù)隨時會修改寺枉,所以整個數(shù)據(jù)處理中需要將數(shù)據(jù)加鎖。悲觀鎖一般都是依靠關(guān)系數(shù)據(jù)庫提供的鎖機(jī)制绷落,事實(shí)上關(guān)系數(shù)據(jù)庫中的行鎖姥闪,表鎖不論是讀寫鎖都是悲觀鎖。
悲觀鎖按照使用性質(zhì)劃分:
1砌烁、共享鎖(Share locks簡記為S鎖):也稱讀鎖筐喳,事務(wù)A對對象T加s鎖,其他事務(wù)也只能對T加S函喉,多個事務(wù)可以同時讀避归,但不能有寫操作,直到A釋放S鎖函似。
2槐脏、排它鎖(Exclusivelocks簡記為X鎖):也稱寫鎖喉童,事務(wù)A對對象T加X鎖以后撇寞,其他事務(wù)不能對T加任何鎖顿天,只有事務(wù)A可以讀寫對象T直到A釋放X鎖。
3蔑担、更新鎖(簡記為U鎖):用來預(yù)定要對此對象施加X鎖牌废,它允許其他事務(wù)讀,但不允許再施加U鎖或X鎖啤握;當(dāng)被讀取的對象將要被更新時鸟缕,則升級為X鎖,主要是用來防止死鎖的排抬。因?yàn)槭褂霉蚕礞i時懂从,修改數(shù)據(jù)的操作分為兩步,首先獲得一個共享鎖蹲蒲,讀取數(shù)據(jù)番甩,然后將共享鎖升級為排它鎖,然后再執(zhí)行修改操作届搁。這樣如果同時有兩個或多個事務(wù)同時對一個對象申請了共享鎖缘薛,在修改數(shù)據(jù)的時候,這些事務(wù)都要將共享鎖升級為排它鎖卡睦。這些事務(wù)都不會釋放共享鎖而是一直等待對方釋放宴胧,這樣就造成了死鎖。如果一個數(shù)據(jù)在修改前直接申請更新鎖表锻,在數(shù)據(jù)修改的時候再升級為排它鎖恕齐,就可以避免死鎖。
七瞬逊、悲觀鎖按照作用范圍劃分:
行鎖:鎖的作用范圍是行級別檐迟,數(shù)據(jù)庫能夠確定那些行需要鎖的情況下使用行鎖,如果不知道會影響哪些行的時候就會使用表鎖码耐。舉個例子追迟,一個用戶表user,有主鍵id和用戶生日birthday當(dāng)你使用update … where id=?這樣的語句數(shù)據(jù)庫明確知道會影響哪一行骚腥,它就會使用行鎖敦间,當(dāng)你使用update … where birthday=?這樣的的語句的時候因?yàn)槭孪炔恢罆绊懩男┬芯涂赡軙褂帽礞i。
表鎖:鎖的作用范圍是整張表束铭。
樂觀鎖:顧名思義廓块,就是很樂觀,每次自己操作數(shù)據(jù)的時候認(rèn)為沒有人回來修改它契沫,所以不去加鎖带猴,但是在更新的時候會去判斷在此期間數(shù)據(jù)有沒有被修改,需要用戶自己去實(shí)現(xiàn)懈万。既然都有數(shù)據(jù)庫提供的悲觀鎖可以方便使用為什么要使用樂觀鎖呢拴清?對于讀操作遠(yuǎn)多于寫操作的時候靶病,大多數(shù)都是讀取,這時候一個更新操作加鎖會阻塞所有讀取口予,降低了吞吐量娄周。最后還要釋放鎖,鎖是需要一些開銷的沪停,我們只要想辦法解決極少量的更新操作的同步問題煤辨。換句話說,如果是讀寫比例差距不是非常大或者你的系統(tǒng)沒有響應(yīng)不及時木张,吞吐量瓶頸問題众辨,那就不要去使用樂觀鎖,它增加了復(fù)雜度舷礼,也帶來了額外的風(fēng)險泻轰。
八、樂觀鎖實(shí)現(xiàn)方式:
版本號(記為version):就是給數(shù)據(jù)增加一個版本標(biāo)識且轨,在數(shù)據(jù)庫上就是表中增加一個version字段浮声,每次更新把這個字段加1,讀取數(shù)據(jù)的時候把version讀出來旋奢,更新的時候比較version泳挥,如果還是開始讀取的version就可以更新了,如果現(xiàn)在的version比老的version大至朗,說明有其他事務(wù)更新了該數(shù)據(jù)屉符,并增加了版本號,這時候得到一個無法更新的通知锹引,用戶自行根據(jù)這個通知來決定怎么處理矗钟,比如重新開始一遍。這里的關(guān)鍵是判斷version和更新兩個動作需要作為一個原子單元執(zhí)行嫌变,否則在你判斷可以更新以后正式更新之前有別的事務(wù)修改了version吨艇,這個時候你再去更新就可能會覆蓋前一個事務(wù)做的更新,造成第二類丟失更新腾啥,所以你可以使用update … where … and version=”old version”這樣的語句东涡,根據(jù)返回結(jié)果是0還是非0來得到通知,如果是0說明更新沒有成功倘待,因?yàn)関ersion被改了疮跑,如果返回非0說明更新成功。
時間戳(timestamp):和版本號基本一樣凸舵,只是通過時間戳來判斷而已祖娘,注意時間戳要使用數(shù)據(jù)庫服務(wù)器的時間戳不能是業(yè)務(wù)系統(tǒng)的時間。
待更新字段:和版本號方式相似啊奄,只是不增加額外字段渐苏,直接使用有效數(shù)據(jù)字段做版本控制信息掀潮,因?yàn)橛袝r候我們可能無法改變舊系統(tǒng)的數(shù)據(jù)庫表結(jié)構(gòu)。假設(shè)有個待更新字段叫count,先去讀取這個count,更新的時候去比較數(shù)據(jù)庫中count的值是不是我期望的值(即開始讀的值)整以,如果是就把我修改的count的值更新到該字段,否則更新失敗峻仇。java的基本類型的原子類型對象如AtomicInteger就是這種思想公黑。
所有字段:和待更新字段類似,只是使用所有字段做版本控制信息摄咆,只有所有字段都沒變化才會執(zhí)行更新凡蚜。
九、樂觀鎖幾種方式的區(qū)別:
新系統(tǒng)設(shè)計可以使用version方式和timestamp方式吭从,需要增加字段朝蜘,應(yīng)用范圍是整條數(shù)據(jù),不論那個字段修改都會更新version,也就是說兩個事務(wù)更新同一條記錄的兩個不相關(guān)字段也是互斥的涩金,不能同步進(jìn)行谱醇。舊系統(tǒng)不能修改數(shù)據(jù)庫表結(jié)構(gòu)的時候使用數(shù)據(jù)字段作為版本控制信息,不需要新增字段步做,待更新字段方式只要其他事務(wù)修改的字段和當(dāng)前事務(wù)修改的字段沒有重疊就可以同步進(jìn)行副渴,并發(fā)性更高。
參考:https://blog.csdn.net/aluomaidi/article/details/52460844
十全度、行為分類
不受保護(hù)的行為(unprotected actions):
不需要進(jìn)行undone/redone
除了一致性煮剧,沒有其他的ACID特性,他們的作用不可以依靠
例如将鸵,在事務(wù)期間對臨時文件的操作
受保護(hù)的行為(protected actions):
可以也必須進(jìn)行undone/redone
在結(jié)束之前不會顯示出結(jié)果勉盅,具有完全的ACID特性
例如,數(shù)據(jù)庫操作
真實(shí)的行為(real action):
不能被undone的操作
這些操作直接作用于物理世界顶掉,非常難或者幾乎不可能進(jìn)行撤銷
ATM機(jī)取錢
十一草娜、事務(wù)的模式
1、平面型事務(wù)(FLAT TRANSACTIONS)
計算的是本地的變量痒筒,無內(nèi)部結(jié)構(gòu)(只有邏輯驱还,沒有存檔點(diǎn)),因此不會被DBMS看到凸克。
且只能面向單一的DBMS议蟆,在同一時間只能運(yùn)行一個事務(wù),
使用調(diào)用或語句級別的接口訪問DBMS萎战,一般開始于Begin咐容,接著是一系列操作,最后以COMMIT或者ROLLBACK結(jié)束蚂维。
只適用于簡單的應(yīng)用戳粒。一旦回滾路狮,則將整個事務(wù)的所有操作進(jìn)行回滾,所有在沒有COMMIT之前的操作全部丟失
2蔚约、帶存檔點(diǎn)的平面型事務(wù)
平面型事務(wù)一旦回滾奄妨,整個事務(wù)的所有操作都要回滾。
存檔點(diǎn)的作用就是苹祟,回滾的時候不需要逐條undo砸抛,可以直接從存檔點(diǎn)開始undo。節(jié)省時間树枫,用空間換時間直焙。
存檔點(diǎn)可以是多個,1砂轻,2奔誓,3。后面的依賴前面的搔涝,如果把存檔點(diǎn)2釋放了厨喂,則存檔點(diǎn)3也自動釋放。
savepoint將事務(wù)變成一系列的每一個都可以單獨(dú)回滾的行為庄呈。
3杯聚、嵌套事務(wù)(NESTED TRANSACTIONS)
嵌套事務(wù)是一套有層次的操作,子事務(wù)的結(jié)果要依賴于它父親事務(wù)的操作抒痒。
比較好理解幌绍,一個事務(wù)調(diào)用另一個被注解事務(wù)的service。
4故响、鏈?zhǔn)绞聞?wù)(Chained Txns)
多個事務(wù)順序執(zhí)行傀广,一個事務(wù)COMMIT之后,另一個事務(wù)馬上BEGIN彩届,沒有事務(wù)可以在兩個事務(wù)之間對數(shù)據(jù)進(jìn)行修改伪冰。必須串行執(zhí)行。
和savepoint不同的地方在于:
COMMIT允許DBMS釋放所有的鎖
后面的子事務(wù)不能回滾到之前的子事務(wù)中去樟蠕,所以該事務(wù)不具備原子性
4.1贮聂、批量更新問題
批量更新(bulk update)本身就是一個天然事務(wù),如果一旦失敗則全部回滾寨辩。
雖然鏈?zhǔn)绞聞?wù)模型解決了這個問題吓懈,但是它要求應(yīng)用自己去解決維護(hù)數(shù)據(jù)庫狀態(tài)、解決失敗操作這些問題靡狞。因?yàn)镈BMS沒有辦法將整個事務(wù)回滾耻警。
5、補(bǔ)償事務(wù)(compensating transactions)
一種特殊類型的事務(wù),用于將之前事務(wù)的操作結(jié)果進(jìn)行消除甘穿。這種消除只能是邏輯層面的腮恩,而不是物理層面的。
不常用温兼。
SAGE事務(wù)
由兩個鏈?zhǔn)绞聞?wù)構(gòu)成秸滴,分別是是T1,T2,…,Tn,和對應(yīng)事務(wù)的補(bǔ)償事務(wù)C1,C2,…,Cn募判。
事務(wù)的提交順序只能是兩種:
按順序提交T1,…,Tn荡含。
按順序提交T1,…,Tj,Cj,…,\C1。
提交按鏈?zhǔn)教峤焕忌耍绻貪L内颗,也按鏈?zhǔn)降腃回滾钧排。
參考:https://blog.csdn.net/u013007900/article/details/77927723
十二敦腔、service層與事務(wù):DAO層執(zhí)行的是對數(shù)據(jù)源的單個操作,service層比較適合作為事務(wù)的存放層恨溜。在service層中調(diào)用DAO層的多個方法符衔,并且使用同一個鏈接對象。
參考:https://www.cnblogs.com/chentingk/p/5864194.html