事務(wù)的四大大特性ACID
· 原子性
事務(wù)必須是原子工作單元长窄;對于其數(shù)據(jù)修改,要么全都執(zhí)行抵恋,要么全都不執(zhí)行焕议。通常,與某個事務(wù)關(guān)聯(lián)的操作具有共同的目標弧关,并且是相互依賴的盅安。如果系統(tǒng)只執(zhí)行這些操作的一個子集唤锉,則可能會破壞事務(wù)的總體目標。原子性消除了系統(tǒng)處理操作子集的可能性别瞭。
· 一致性
事務(wù)在完成時窿祥,必須使所有的數(shù)據(jù)都保持一致狀態(tài)。在相關(guān)數(shù)據(jù)庫中蝙寨,所有規(guī)則都必須應(yīng)用于事務(wù)的修改晒衩,以保持所有數(shù)據(jù)的完整性。事務(wù)結(jié)束時墙歪,所有的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(如 B 樹索引或雙向鏈表)都必須是正確的听系。某些維護一致性的責(zé)任由應(yīng)用程序開發(fā)人員承擔(dān),他們必須確保應(yīng)用程序已強制所有已知的完整性約束虹菲。例如跛锌,當(dāng)開發(fā)用于轉(zhuǎn)帳的應(yīng)用程序時,應(yīng)避免在轉(zhuǎn)帳過程中任意移動小數(shù)點届惋。
· 隔離性
由并發(fā)事務(wù)所作的修改必須與任何其它并發(fā)事務(wù)所作的修改隔離髓帽。事務(wù)查看數(shù)據(jù)時數(shù)據(jù)所處的狀態(tài),要么是另一并發(fā)事務(wù)修改它之前的狀態(tài)脑豹,要么是另一事務(wù)修改它之后的狀態(tài)郑藏,事務(wù)不會查看中間狀態(tài)的數(shù)據(jù)。這稱為可串行性瘩欺,因為它能夠重新裝載起始數(shù)據(jù)必盖,并且重播一系列事務(wù),以使數(shù)據(jù)結(jié)束時的狀態(tài)與原始事務(wù)執(zhí)行的狀態(tài)相同俱饿。當(dāng)事務(wù)可序列化時將獲得最高的隔離級別歌粥。在此級別上,從一組可并行執(zhí)行的事務(wù)獲得的結(jié)果與通過連續(xù)運行每個事務(wù)所獲得的結(jié)果相同拍埠。由于高度隔離會限制可并行執(zhí)行的事務(wù)數(shù)失驶,所以一些應(yīng)用程序降低隔離級別以換取更大的吞吐量。
· 持久性
事務(wù)完成之后枣购,它對于系統(tǒng)的影響是永久性的嬉探。該修改即使出現(xiàn)致命的系統(tǒng)故障也將一直保持。
四種隔離級別
Read Uncommitted(讀取未提交內(nèi)容)
在該隔離級別棉圈,所有事務(wù)都可以看到其他未提交事務(wù)的執(zhí)行結(jié)果涩堤。本隔離級別很少用于實際應(yīng)用,因為它的性能也不比其他級別好多少分瘾。讀取未提交的數(shù)據(jù)胎围,也被稱之為臟讀(Dirty Read)。
Read Committed(讀取提交內(nèi)容)
這是大多數(shù)數(shù)據(jù)庫系統(tǒng)的默認隔離級別(但不是MySQL默認的)。它滿足了隔離的簡單定義:一個事務(wù)只能看見已經(jīng)提交事務(wù)所做的改變白魂。這種隔離級別 也支持所謂的不可重復(fù)讀(Nonrepeatable Read)汽纤,因為同一事務(wù)的其他實例在該實例處理其間可能會有新的commit,所以同一select可能返回不同結(jié)果碧聪。
Repeatable Read(可重讀)
這是MySQL的默認事務(wù)隔離級別冒版,它確保同一事務(wù)的多個實例在并發(fā)讀取數(shù)據(jù)時液茎,會看到同樣的數(shù)據(jù)行逞姿。不過理論上,這會導(dǎo)致另一個棘手的問題:幻讀 (Phantom Read)捆等。簡單的說滞造,幻讀指當(dāng)用戶讀取某一范圍的數(shù)據(jù)行時,另一個事務(wù)又在該范圍內(nèi)插入了新行栋烤,當(dāng)用戶再讀取該范圍的數(shù)據(jù)行時谒养,會發(fā)現(xiàn)有新的“幻影” 行。InnoDB和Falcon存儲引擎通過多版本并發(fā)控制(MVCC明郭,Multiversion Concurrency Control)機制解決了該問題买窟。
Serializable(可串行化)
這是最高的隔離級別,它通過強制事務(wù)排序薯定,使之不可能相互沖突始绍,從而解決幻讀問題。簡言之话侄,它是在每個讀的數(shù)據(jù)行上加上共享鎖亏推。在這個級別,可能導(dǎo)致大量的超時現(xiàn)象和鎖競爭年堆。
這四種隔離級別采取不同的鎖類型來實現(xiàn)吞杭,若讀取的是同一個數(shù)據(jù)的話,就容易發(fā)生問題变丧。例如:
臟讀(Drity Read):某個事務(wù)已更新一份數(shù)據(jù)芽狗,另一個事務(wù)在此時讀取了同一份數(shù)據(jù),由于某些原因痒蓬,前一個RollBack了操作译蒂,則后一個事務(wù)所讀取的數(shù)據(jù)就會是不正確的。
不可重復(fù)讀(Non-repeatable read):在一個事務(wù)的兩次查詢之中數(shù)據(jù)不一致谊却,這可能是兩次查詢過程中間插入了一個事務(wù)更新的原有的數(shù)據(jù)柔昼。
幻讀(Phantom Read):在一個事務(wù)的兩次查詢中數(shù)據(jù)筆數(shù)不一致,例如有一個事務(wù)查詢了幾列(Row)數(shù)據(jù)炎辨,而另一個事務(wù)卻在此時插入了新的幾列數(shù)據(jù)捕透,先前的事務(wù)在接下來的查詢中,就會發(fā)現(xiàn)有幾列數(shù)據(jù)是它先前所沒有的。
關(guān)于數(shù)據(jù)庫的各種鎖的總結(jié):
1.共享鎖(又稱讀鎖)乙嘀、排它鎖(又稱寫鎖):
InnoDB引擎的鎖機制:InnoDB支持事務(wù)末购,支持行鎖和表鎖用的比較多,Myisam不支持事務(wù)虎谢,只支持表鎖盟榴。
共享鎖(S):允許一個事務(wù)去讀一行,阻止其他事務(wù)獲得相同數(shù)據(jù)集的排他鎖婴噩。
排他鎖(X):允許獲得排他鎖的事務(wù)更新數(shù)據(jù)擎场,阻止其他事務(wù)取得相同數(shù)據(jù)集的共享讀鎖和排他寫鎖。
意向共享鎖(IS):事務(wù)打算給數(shù)據(jù)行加行共享鎖几莽,事務(wù)在給一個數(shù)據(jù)行加共享鎖前必須先取得該表的IS鎖迅办。
意向排他鎖(IX):事務(wù)打算給數(shù)據(jù)行加行排他鎖,事務(wù)在給一個數(shù)據(jù)行加排他鎖前必須先取得該表的IX鎖章蚣。
說明:
1)共享鎖和排他鎖都是行鎖站欺,意向鎖都是表鎖,應(yīng)用中我們只會使用到共享鎖和排他鎖纤垂,意向鎖是mysql內(nèi)部使用的矾策,不需要用戶干預(yù)。
2)對于UPDATE峭沦、DELETE和INSERT語句贾虽,InnoDB會自動給涉及數(shù)據(jù)集加排他鎖(X);對于普通SELECT語句熙侍,InnoDB不會加任何鎖榄鉴,事務(wù)可以通過以下語句顯示給記錄集加共享鎖或排他鎖。
共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE蛉抓。
排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE庆尘。
**對于鎖定行記錄后需要進行更新操作的應(yīng)用,應(yīng)該使用Select...For update 方式巷送,獲取排它鎖驶忌。(用共享鎖,在讀了之后再寫會阻塞笑跛,會導(dǎo)致死鎖)
這里說說Myisam:MyISAM在執(zhí)行查詢語句(SELECT)前付魔,會自動給涉及的所有表加讀鎖,在執(zhí)行更新操作(UPDATE飞蹂、DELETE几苍、INSERT等)前,會自動給涉及的表加寫鎖陈哑。
3)InnoDB行鎖是通過給索引上的索引項加鎖來實現(xiàn)的妻坝,因此InnoDB這種行鎖實現(xiàn)特點意味著:只有通過索引條件檢索數(shù)據(jù)伸眶,InnoDB才使用行級鎖,否則刽宪,InnoDB將使用表鎖厘贼!
2.樂觀鎖、悲觀鎖:
悲觀鎖:悲觀鎖圣拄,正如其名嘴秸,它指的是對數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù),以及來自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度庇谆,因此岳掐,在整個數(shù)據(jù)處理過程中,將數(shù)據(jù)處于鎖定狀態(tài)族铆。悲觀鎖的實現(xiàn)岩四,往往依靠數(shù)據(jù)庫提供的鎖機制(也只有數(shù)據(jù)庫層提供的鎖機制才能真正保證數(shù)據(jù)訪問的排他性哭尝,否則哥攘,即使在本系統(tǒng)中實現(xiàn)了加鎖機制,也無法保證外部系統(tǒng)不會修改數(shù)據(jù))
1)使用悲觀鎖材鹦,我們必須關(guān)閉mysql數(shù)據(jù)庫的自動提交屬性逝淹,采用手動提交事務(wù)的方式,因為MySQL默認使用autocommit模式桶唐,也就是說栅葡,當(dāng)你執(zhí)行一個更新操作后,MySQL會立刻將結(jié)果進行提交尤泽。
2)需要注意的是欣簇,在事務(wù)中,只有SELECT ... FOR UPDATE 或LOCK IN SHARE MODE 同一筆數(shù)據(jù)時會等待其它事務(wù)結(jié)束后才執(zhí)行坯约,一般SELECT ... 則不受此影響熊咽。對于UPDATE、DELETE和INSERT語句闹丐,InnoDB會自動給涉及數(shù)據(jù)集加排他鎖(X)横殴。
3)補充:MySQL select…for update的Row Lock與Table Lock
使用select…for update會把數(shù)據(jù)給鎖住,不過我們需要注意一些鎖的級別卿拴,MySQL InnoDB默認Row-Level Lock衫仑,所以只有「明確」地指定主鍵(或有索引的地方),MySQL 才會執(zhí)行Row lock (只鎖住被選取的數(shù)據(jù)) 堕花,否則MySQL 將會執(zhí)行Table Lock (將整個數(shù)據(jù)表單給鎖住)文狱。
樂觀鎖:
樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設(shè)認為數(shù)據(jù)一般情況下不會造成沖突缘挽,所以在數(shù)據(jù)進行提交更新的時候瞄崇,才會正式對數(shù)據(jù)的沖突與否進行檢測陷虎,如果發(fā)現(xiàn)沖突了,則讓返回用戶錯誤的信息杠袱,讓用戶決定如何去做(一般是回滾事務(wù))尚猿。那么我們?nèi)绾螌崿F(xiàn)樂觀鎖呢,一般來說有以下2種方式:
1).使用數(shù)據(jù)版本(Version)記錄機制實現(xiàn)楣富,這是樂觀鎖最常用的一種實現(xiàn)方式凿掂。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個版本標識纹蝴,一般是通過為數(shù)據(jù)庫表增加一個數(shù)字類型的 “version” 字段來實現(xiàn)庄萎。當(dāng)讀取數(shù)據(jù)時,將version字段的值一同讀出塘安,數(shù)據(jù)每更新一次糠涛,對此version值加一。當(dāng)我們提交更新的時候兼犯,判斷數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息與第一次取出來的version值進行比對忍捡,如果數(shù)據(jù)庫表當(dāng)前版本號與第一次取出來的version值相等,則予以更新切黔,否則認為是過期數(shù)據(jù)砸脊。
2).樂觀鎖定的第二種實現(xiàn)方式和第一種差不多,同樣是在需要樂觀鎖控制的table中增加一個字段纬霞,名稱無所謂凌埂,字段類型使用時間戳(timestamp), 和上面的version類似,也是在更新提交的時候檢查當(dāng)前數(shù)據(jù)庫中數(shù)據(jù)的時間戳和自己更新前取到的時間戳進行對比诗芜,如果一致則OK瞳抓,否則就是版本沖突。
總結(jié):兩種鎖各有優(yōu)缺點伏恐,不可認為一種好于另一種孩哑,像樂觀鎖適用于寫比較少的情況下,即沖突真的很少發(fā)生的時候脐湾,這樣可以省去了鎖的開銷臭笆,加大了系統(tǒng)的整個吞吐量。但如果經(jīng)常產(chǎn)生沖突秤掌,上層應(yīng)用會不斷的進行retry愁铺,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適闻鉴。
另外茵乱,高并發(fā)情況下個人認為樂觀鎖要好于悲觀鎖,因為悲觀鎖的機制使得各個線程等待時間過長孟岛,極其影響效率瓶竭,樂觀鎖可以在一定程度上提高并發(fā)度督勺。
3.表鎖、行鎖
表級鎖(table-level locking):MyISAM和MEMORY存儲引擎
行級鎖(row-level locking) :InnoDB存儲引擎
頁面鎖(page-level-locking):BDB存儲引擎
表級鎖:開銷小斤贰,加鎖快;不會出現(xiàn)死鎖;鎖定粒度大智哀,發(fā)生鎖沖突的概率最高,并發(fā)度最低。
行級鎖:開銷大荧恍,加鎖慢;會出現(xiàn)死鎖;鎖定粒度最小瓷叫,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間;會出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間送巡,并發(fā)度一般摹菠。
Mysql 查看及設(shè)置事物隔離級別
1.查看
SELECT @@tx_isolation
2.設(shè)置
2.1所有級別
1)read uncommitted : 讀取尚未提交的數(shù)據(jù) :哪個問題都不能解決
2)read committed:讀取已經(jīng)提交的數(shù)據(jù) :可以解決臟讀 ---- oracle默認的
3)repeatable read:重讀讀取:可以解決臟讀 和 不可重復(fù)讀 ---mysql默認的
4)serializable:串行化:可以解決 臟讀 不可重復(fù)讀 和 虛讀---相當(dāng)于鎖表
2.2 設(shè)置
設(shè)置mysql的隔離級別:set session transaction isolation level 設(shè)置事務(wù)隔離級別
全局修改骗爆,修改mysql.ini配置文件次氨,在最后加上
1 #可選參數(shù)有:READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE.
2 [mysqld]
3 transaction-isolation = REPEATABLE-READ