日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

MySQL的事务与事务隔离

發(fā)布時間:2023/12/31 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL的事务与事务隔离 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?? MySQL中自從引入InnoDB引擎后,在MySQL中就支持事務(wù),事務(wù)就是一組原子性的查詢語句,也即將多個查詢當作一個獨立的工作單元,平時通過提交工作單元來完成在事務(wù)中的相應(yīng)的查詢或修改,在能支持事務(wù)的數(shù)據(jù)庫中必須要滿足ACID測試,即事務(wù)的四個特性:

????A:Atomicity,原子性(都執(zhí)行或者都不執(zhí)行)

????C:Consistency,一致性(從一個一致性狀態(tài)轉(zhuǎn)到另外一個一致性狀態(tài))

????I:Isolaction,隔離性(一個事務(wù)的所有修改操作在提交前對其他事務(wù)時不可見的)

????D: Durability,持久性(旦事務(wù)得到提交,其所做的修改會永久有效)

而在早期默認的引擎MyISAM是不支持事務(wù)的,所以如果是在MyISAM表中是不支持事物的,想要知道數(shù)據(jù)中具體支持哪些表引擎可以通過”SHOW ENGINES;”查看在所使用版本中MySQL所支持的所有引擎。在這里先創(chuàng)建一張表transaction_tbl用于測試:

CREATE?TABLE?transaction_tbl?(id?int(4))?ENGINE=InnoDB;? INSERT?INTO?transaction_tbl?VALUE?(1); INSERT?INTO?transaction_tbl?VALUE?(2); INSERT?INTO?transaction_tbl?VALUE?(3); INSERT?INTO?transaction_tbl?VALUE?(4); INSERT?INTO?transaction_tbl?VALUE?(5);

在正常的使用過程中需要關(guān)閉自動提交的功能默認系統(tǒng)下是開啟的

mysql>?SHOW?GLOBAL?VARIABLES?LIKE?'autocommit';??????????????????????? +---------------+-------+ |?Variable_name?|?Value?| +---------------+-------+ |?autocommit????|?ON????| +---------------+-------+ 1?row?in?set?(0.00?sec)

在使用事務(wù)之前需要關(guān)閉,在平時使用事務(wù)之前需要先檢查是否有開啟autocommit,當然如果對事務(wù)的依賴比較大建議可以永久關(guān)閉全局的自動提交,但是在平時使用的過程中只要在使用時關(guān)閉自動提交,而使用手動啟動事務(wù),這樣在事務(wù)中需要回滾時才能根據(jù)相關(guān)的事務(wù)隔離級別得到想要的效果,可以在使用事務(wù)時關(guān)閉autocommit,在所有的事務(wù)結(jié)束后再開啟autocommit

mysql>?SET?GLOBAL?AUTOCOMMIT=off;#當然這里也可以使用布爾值的0和1 Query?OK,?0?rows?affected?(0.00?sec)

其中事務(wù)的控制語句也很簡單,如下:

BEGIN;?或?START?TRANSACTION; 顯式地開啟一個事務(wù)COMMIT; 提交事務(wù)即結(jié)束事務(wù),并使已對數(shù)據(jù)庫進行的所有修改為持久性的ROLLBACK; 事務(wù)回滾,會結(jié)束用戶的事務(wù)并撤銷正在進行的所有未提交的修改SAVEPOINT?identifier; 允許在事務(wù)中創(chuàng)建一個保存點,一個事務(wù)中可以有多個SAVEPOINTRELEASE?SAVEPOINT?identifier; 刪除一個事務(wù)的保存點,當沒有指定的保存點時,執(zhí)行該SQL語句會報異常ROLLBACK?TO?identifier; 把事務(wù)回滾到標記點

而在事務(wù)中的隔離級別不同,則事物的安全性就不同,但是事物得安全性越高,并發(fā)性越低,當然需要根據(jù)實際情況選擇,在MySQL中事務(wù)的隔離級別有四種,安全級分別由低至高:

????READ UNCOMMITTEND:讀未提交

????READ COMMITTEND:讀提交

????REPEATABLE READ :可重讀

????SERIALIZABLE:可串行化

查看當前使用的默認的事務(wù)隔離級別:

mysql>?SHOW?GLOBAL?VARIABLES?LIKE?'tx_isolation'; +---------------+-----------------+ |?Variable_name?|?Value???????????| +---------------+-----------------+ |?tx_isolation??|?REPEATABLE-READ?| +---------------+-----------------+ 1?row?in?set?(0.00?sec)

而在使用四個隔離級別中,所帶來效果都是不相同的,此時測試需要開啟2個session更為直觀,在這里就用A、B來代表兩個session中開啟事務(wù)A、B:

mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??1?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.01?sec)

??? 一、READ UNCOMMITTEND:讀未提交,顧名思義即所有的事務(wù)都可以讀取到其他事務(wù)中未提交的內(nèi)容,該隔離模式在平時一般都不使用,因為使用READ UNCOMMITTEND會帶來臟讀問題,下面就用transaction_tbl舉一個簡單例子說明下:

A、B中:

mysql>?SET?tx_isolation='READ-UNCOMMITTED'; Query?OK,?0?rows?affected?(0.00?sec) mysql>?SHOW?VARIABLES?LIKE?'tx_isolation'; +---------------+------------------+ |?Variable_name?|?Value????????????| +---------------+------------------+ |?tx_isolation??|?READ-UNCOMMITTED?| +---------------+------------------+ 1?row?in?set?(0.00?sec)

事務(wù)A中做了操作,但不提交:

mysql>?START?TRANSACTION; Query?OK,?0?rows?affected?(0.00?sec)mysql>?UPDATE?transaction_tbl?SET?id?=?'6'?WHERE?id='1'; Query?OK,?1?row?affected?(0.02?sec) Rows?matched:?1??Changed:?1??Warnings:?0mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??6?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.00?sec)

但是此時事務(wù)B是可以看見事務(wù)A中數(shù)據(jù)

事務(wù)B:

mysql>?START?TRANSACTION; Query?OK,?0?rows?affected?(0.00?sec)mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??6?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.01?sec)

此時事務(wù)A回滾:

mysql>?ROLLBACK; Query?OK,?0?rows?affected?(0.01?sec)mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??1?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.00?sec)

事務(wù)B中查出來的是事務(wù)A中未提交的數(shù)據(jù):

mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??1?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.00?sec)

這樣就是由READ UNCOMMITTEND所帶來的臟讀,一般數(shù)據(jù)庫生產(chǎn)環(huán)境中都不用這種事務(wù)隔離級別。

????二、READ COMMITTEND,讀提交,同理根據(jù)名字可知事物的隔離級別會比讀未提交高一個事務(wù)隔離級別更高,從而解決了臟讀的問題,這也是大多數(shù)數(shù)據(jù)庫中所用的默認事務(wù)隔離級別,但并不是MySQL的默認事務(wù)隔離級別,該事務(wù)隔離級別雖然解決了臟讀問題,但是帶來新的問題是不可重讀,如果此時恰好有2個事務(wù)對相同的一張表做操作時,在一個事務(wù)中執(zhí)行相同的查詢時會查出不同的結(jié)果:

A、B中:

mysql>?SET?tx_isolation='READ-COMMITTED'; Query?OK,?0?rows?affected?(0.00?sec)mysql>?SHOW?VARIABLES?LIKE?'tx_isolation';??????? +---------------+----------------+ |?Variable_name?|?Value??????????| +---------------+----------------+ |?tx_isolation??|?READ-COMMITTED?| +---------------+----------------+ 1?row?in?set?(0.00?sec)

在事務(wù)A中:

mysql>?BEGIN; Query?OK,?0?rows?affected?(0.00?sec)mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??1?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.00?sec)

此時事務(wù)B中也開啟事務(wù)做了一個操作:

mysql>?BEGIN; Query?OK,?0?rows?affected?(0.00?sec)mysql>?UPDATE?transaction_tbl?SET?id?=?'6'?WHERE?id='1'; Query?OK,?1?row?affected?(0.00?sec) Rows?matched:?1??Changed:?1??Warnings:?0mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??6?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.01?sec)

此時看下事務(wù)A中的查詢:

mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??1?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.00?sec) #但此時事務(wù)B中COMMIT提交后,事務(wù)A中 mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??6?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.00?sec)

這樣就是由READ COMMITTEND所帶來的不可重讀問題,所以在一般數(shù)據(jù)庫生產(chǎn)環(huán)境中也不建議采用這種事務(wù)隔離級別。

????三、REPEATABLE READ,可重讀,同理該事務(wù)隔離級別解決了不可重讀的問題,在REPEATABLE READ中使用MVCC(多版本并發(fā)控制)在每個事務(wù)啟動時,InnoDB會為每個啟動的事務(wù)提供一個當下時刻的快照,為實現(xiàn)此功能,InnoDB會為每個表提供兩隱藏的字段,一個用于保存行的創(chuàng)建時間,一個用于保存行的失效時間,里面存儲的系統(tǒng)版本號,MVCC旨在READ COMMITTEND和REPEATABLE READ兩個事務(wù)隔離中生效,但是在REPEATABLE READ同以上事務(wù)隔離級別一樣,在解決了不可重讀的問題同時也帶來新的問題幻讀,此時恰好有2個事務(wù)對相同的一張表做操作時,在一個事務(wù)中提交之前其中一個事務(wù)在另一事務(wù)提交前后查詢的結(jié)果不一樣:

A、B中:

mysql>?SET?tx_isolation='REPEATABLE-READ';? Query?OK,?0?rows?affected?(0.01?sec)mysql>?SHOW?VARIABLES?LIKE?'tx_isolation'; +---------------+-----------------+ |?Variable_name?|?Value???????????| +---------------+-----------------+ |?tx_isolation??|?REPEATABLE-READ?| +---------------+-----------------+ 1?row?in?set?(0.01?sec)

事務(wù)A:

mysql>?BEGIN; Query?OK,?0?rows?affected?(0.00?sec)mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??6?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.02?sec)

事務(wù)B中做相關(guān)操作并提交:

mysql>?BEGIN; Query?OK,?0?rows?affected?(0.00?sec)mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??6?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.00?sec)mysql>?UPDATE?transaction_tbl?SET?id?=?'1'?WHERE?id='6'; Query?OK,?1?row?affected?(0.00?sec) Rows?matched:?1??Changed:?1??Warnings:?0mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??1?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.01?sec)mysql>?COMMIT; Query?OK,?0?rows?affected?(0.02?sec)

此時再來看下事務(wù)A中:

mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??1?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.02?sec)mysql>?COMMIT; Query?OK,?0?rows?affected?(0.00?sec)mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??6?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.00?sec)

這樣就是REPEATABLE READ帶來的幻讀問題,當然在實際生產(chǎn)中這么恰好的事比較少,所以一般都做為MySQL的默認事務(wù)隔離級別。

????四、SERIALIZABLE,可串行化,強事務(wù)排序也是最高級別的事務(wù)隔離,所有的事務(wù)都有使用共享鎖,這樣就解決相應(yīng)的幻讀問題,但是因為共享鎖的原因從而使寫入的性能降低,從而降低了MySQL的性能:

A、B中:

mysql>?SET?tx_isolation='SERIALIZABLE'; Query?OK,?0?rows?affected?(0.00?sec)mysql>?SHOW?VARIABLES?LIKE?'tx_isolation'; +---------------+--------------+ |?Variable_name?|?Value????????| +---------------+--------------+ |?tx_isolation??|?SERIALIZABLE?| +---------------+--------------+ 1?row?in?set?(0.00?sec)

在事務(wù)A中插入一條數(shù)據(jù)不提交:

mysql>?BEGIN; Query?OK,?0?rows?affected?(0.00?sec)mysql>?INSERT?INTO?transaction_tbl?VALUE?('7'); Query?OK,?1?row?affected?(0.00?sec)mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??1?| |??2?| |??3?| |??4?| |??5?| |??7?| +----+ 6?rows?in?set?(0.00?sec)

此時在事務(wù)B中,在事務(wù)A未提交前是無法寫入提交的

mysql>?SHOW?GLOBAL?VARIABLES?LIKE?'tx_isolation'; +---------------+--------------+ |?Variable_name?|?Value????????| +---------------+--------------+ |?tx_isolation??|?SERIALIZABLE?| +---------------+--------------+ 1?row?in?set?(0.00?sec)mysql>?BEGIN; Query?OK,?0?rows?affected?(0.00?sec)mysql>?SELECT?*?FROM?transaction_tbl; +----+ |?id?| +----+ |??1?| |??2?| |??3?| |??4?| |??5?| +----+ 5?rows?in?set?(0.00?sec)mysql>?UPDATE?transaction_tbl?SET?id?=?'6'?WHERE?id='1'; ERROR?1205?(HY000):?Lock?wait?timeout?exceeded;?try?restarting?transaction

只有在事務(wù)A中COMMIT提交后才能在事務(wù)B中做相關(guān)的寫入,但是在此需要注意的是在MySQL 中都是默認都是使用REPEATABLE READ的事務(wù)隔離級別,而在平時利用事務(wù)時多用于存儲過程中大量使用,而不同數(shù)據(jù)庫,語法差別很大,移植困難,換了數(shù)據(jù)庫,需要重新編寫,所以把過多業(yè)務(wù)邏輯寫在存儲過程不好維護,不利于分層管理,容易混亂,一般存儲過程適用于個別對性能要求較高的業(yè)務(wù),其它的必要性不是很大,在平時使用需要根據(jù)實際情況而定。

轉(zhuǎn)載于:https://blog.51cto.com/jim123/1964004

總結(jié)

以上是生活随笔為你收集整理的MySQL的事务与事务隔离的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。