MySQL事務(wù)(transaction)看這篇就足夠了
MySQL事務(wù)處理(TransAction)
思考了很久,決定寫一篇關(guān)于mysql事務(wù)(transaction)的博客,一來嘛,因為最近在復(fù)習mysql的相關(guān)知識,幫自己回顧總結(jié)一下,其次就是想把這篇博客分享給大家,如果你才剛剛開始學習mysql,那么希望這篇博客對你有一點啟發(fā);亦或者你早已是一個mysql老油條,這篇博客也會使你對mysql事務(wù)有一個更深的印象。
首先,什么是事務(wù)呢?
事務(wù)就是由單獨單元的一個或多個sql語句組成,在這個單元中,每個sql語句都是相互依賴的。而整個單獨單元是作為一個不可分割的整體存在,類似于物理當中的原子(一種不可分割的最小單位)。
往通俗的講就是,事務(wù)就是一個整體,里面的內(nèi)容要么都執(zhí)行成功,要么都不成功。不可能存在部分執(zhí)行成功而部分執(zhí)行不成功的情況。
就是說如果單元中某條sql語句一旦執(zhí)行失敗或者產(chǎn)生錯誤,那么整個單元將會回滾(返回最初狀態(tài))。所有受到影響的數(shù)據(jù)將返回到事務(wù)開始之前的狀態(tài),但是如果單元中的所有sql語句都執(zhí)行成功的話,那么該事務(wù)也就被順利執(zhí)行。
大家都知道,我們的數(shù)據(jù)都是通過各種不同技術(shù)的存儲引擎來引導(dǎo)存儲的,不同的存儲引擎,都有各自的特點。在mysql中,常見的存儲引擎有innodb、myisam,memory等。其中innodb支持事務(wù)(transaction),而myisam,memory等不支持事務(wù)。
可以通過
show engines;
語句來查看mysql支持的存儲引擎
一、事務(wù)的四個特性(ACID)【面試常考項】
- 原子性(Atomicity):指事務(wù)是一個不可分割的最小工作單位,事務(wù)中的操作只有都發(fā)生和都不發(fā)生兩種情況
- 一致性(Consistency):事務(wù)必須使數(shù)據(jù)庫從一個一致狀態(tài)變換到另外一個一致狀態(tài),舉一個栗子,李二給王五轉(zhuǎn)賬50元,其事務(wù)就是讓李二賬戶上減去50元,王五賬戶上加上50元;一致性是指其他事務(wù)看到的情況是要么李二還沒有給王五轉(zhuǎn)賬的狀態(tài),要么王五已經(jīng)成功接收到李二的50元轉(zhuǎn)賬。而對于李二少了50元,王五還沒加上50元這個中間狀態(tài)是不可見的。
- 隔離性(Isolation):一個事務(wù)的執(zhí)行不能被其他事務(wù)干擾,即一個事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對并發(fā)的其他事務(wù)是隔離的,并發(fā)執(zhí)行的各個事務(wù)之間不能互相干擾。
- 持久性(Durability):一個事務(wù)一旦提交成功,它對數(shù)據(jù)庫中數(shù)據(jù)的改變將是永久性的,接下來的其他操作或故障不應(yīng)對其有任何影響。
二、事務(wù)的分類
事務(wù)分為隱式事務(wù)和顯式事務(wù)兩種。我們的DML語句(insert、update、delete)就是隱式事務(wù)。
1.隱式事務(wù):該事務(wù)沒有明顯的開啟和結(jié)束標記,它們都具有自動提交事務(wù)的功能;不妨思考一下,update語句修改數(shù)據(jù)時,是不是對表中數(shù)據(jù)進行改變了,它的本質(zhì)其實就相當于一個事務(wù)。
舉一個栗子:張三同學買了一個csdn定制保溫杯花了99元,是不是就是update語句對字段name為張三的同學的余額balance進行減99元的處理呢?代碼如下:
2.顯示事務(wù):該事務(wù)具有明顯的開啟和結(jié)束標記;也是本文重點要講的東西。使用顯式事務(wù)的前提是你得先把自動提交事務(wù)的功能給禁用。禁用自動提交功能就是設(shè)置autocommit
變量值為0(0:禁用 1:開啟)
先查看一下當前的autocommit變量值,發(fā)現(xiàn)當前處于開啟自動提交事務(wù)的狀態(tài)
禁用自動提交事務(wù)的功能并查看當前狀態(tài)
三、開啟事務(wù)的步驟
假設(shè)t_account表已經(jīng)存在
#步驟一:開啟事務(wù)(可選) start transaction; #步驟二:編寫事務(wù)中的sql語句(insert、update、delete) #這里實現(xiàn)一下"李二給王五轉(zhuǎn)賬"的事務(wù)過程 update t_account set balance = 50 where vname = "李二"; update t_account set balance = 130 where vname = "王五"; #步驟三:結(jié)束事務(wù) commit; #提交事務(wù) # rollback; #回滾事務(wù):就是事務(wù)不執(zhí)行,回滾到事務(wù)執(zhí)行前的狀態(tài)
運行結(jié)果:
四、事務(wù)并發(fā)時出現(xiàn)的問題
但是呢,因為某一刻不可能總只有一個事務(wù)在運行,可能出現(xiàn)A在操作t_account表中的數(shù)據(jù),B也同樣在操作t_account表,那么就會出現(xiàn)并發(fā)問題,對于同時運行的多個事務(wù),當這些事務(wù)訪問數(shù)據(jù)庫中相同的數(shù)據(jù)時,如果沒有采用必要的隔離機制,就會發(fā)生以下各種并發(fā)問題。
- ??臟讀:對于兩個事務(wù)T1,T2,T1讀取了已經(jīng)被T2更新但還沒有被提交的字段之后,若T2回滾,T1讀取的內(nèi)容就是臨時且無效的
- ??不可重復(fù)讀 :對于兩個事務(wù)T1,T2,T1讀取了一個字段,然后T2更新了該字段之后,T1在讀取同一個字段,值就不同了
- ?? 幻讀:對于兩個事務(wù)T1,T2,T1在A表中讀取了一個字段,然后T2又在A表中插入了一些新的數(shù)據(jù)時,T1再讀取該表時,就會發(fā)現(xiàn)神不知鬼不覺的多出幾行了…
所以,為了避免以上出現(xiàn)的各種并發(fā)問題,我們就必然要采取一些手段。mysql數(shù)據(jù)庫系統(tǒng)提供了四種事務(wù)的隔離級別,用來隔離并發(fā)運行各個事務(wù),使得它們相互不受影響,這就是數(shù)據(jù)庫事務(wù)的隔離性。
五、事務(wù)的隔離級別
mysql中的四種事務(wù)隔離級別如下:
1. read uncommitted(讀未提交數(shù)據(jù)):允許事務(wù)讀取未被其他事務(wù)提交的變更。(臟讀、不可重復(fù)讀和幻讀的問題都會出現(xiàn))。
2. read committed(讀已提交數(shù)據(jù)):只允許事務(wù)讀取已經(jīng)被其他事務(wù)提交的變更。(可以避免臟讀,但不可重復(fù)讀和幻讀的問題仍然可能出現(xiàn))
3.repeatable read(可重復(fù)讀):確保事務(wù)可以多次從一個字段中讀取相同的值,在這個事務(wù)持續(xù)期間,禁止其他事務(wù)對這個字段進行更新(update)。(可以避免臟讀和不可重復(fù)讀,但幻讀仍然存在)
4. serializable(串行化):確保事務(wù)可以從一個表中讀取相同的行,在這個事務(wù)持續(xù)期間,禁止其他事務(wù)對該表執(zhí)行插入、更新和刪除操作,所有并發(fā)問題都可避免,但性能十分低下(因為你不完成就都不可以弄,效率太低)
了解: oracle支持兩種事務(wù)隔離級別:read committed、serializable。
oracle默認的事務(wù)隔離級別是:read committed。
mysql的默認事務(wù)隔離級別是:repeatable read。
一個事務(wù)與其他事務(wù)隔離的程度稱為隔離級別。數(shù)據(jù)庫規(guī)定了多種事務(wù)隔離級別,不同隔離級別對應(yīng)不同的干擾程度,隔離級別越高,數(shù)據(jù)一致性就越好,但并發(fā)性就越差。
這里通過一個例子向大家簡單介紹一下并發(fā):
一個人?? 在邊開車?? 邊打電話??,首先,人只有一個大腦(cpu),但是在同一時刻他卻在執(zhí)行2件事情,其實內(nèi)部就是靠他的大腦在不斷的切換執(zhí)行,之所以人民警察?? 不允許司機開車時打電話,就是怕人腦在那一瞬間切換不過來,從而導(dǎo)致交通事故的發(fā)生,并發(fā)和這個例子是差不多的意思。但在這里,電腦cpu可比人腦快多了,所以出錯的概率也相對來說小很多。
接一下,演示一下在幾種不同的事務(wù)隔離級別下所發(fā)生的不同情況?? 。
在演示之前呢,還需要知道如何查看和設(shè)置事務(wù)的隔離級別
查看當前的事務(wù)隔離級別通過
tx_isolation
變量或者transaction_isolation
(版本8.0以上使用);語法:select @@tx_isolation;
注意:在mysql8.0之后,就已經(jīng)拋棄了tx_isolation變量了,而是用
transaction_isolation
變量代替了。語法:select @@transaction_isolation;
#設(shè)置當前mysql連接的隔離級別: set session transaction isolation level read uncommitted; #設(shè)置數(shù)據(jù)庫系統(tǒng)的全局的隔離級別: set global transaction isolation level read uncommitted;
注意:當前mysql連接的隔離級別和mysql全局的隔離級別的區(qū)別是什么?
如果只設(shè)置當前的隔離級別,也就是session,那么另外一個并發(fā)的“mysqy程序”的隔離級別不會受到當前連接的影響,而是保持默認的repeatable read。
但是如果是設(shè)置全局的事務(wù)隔離級別,則整個mysql數(shù)據(jù)庫(包括所有打開的mysql程序連接)的隔離級別都會隨之改變,除非服務(wù)器重啟,不然就不會恢復(fù)默認了。
兩者僅僅一詞之差,其效果卻天差地別。
好,了解完如何設(shè)置事務(wù)的隔離級別之后,下面將正式進入…
呃呃呃… 等一下
這里的講解主要是為了知道在并發(fā)的環(huán)境下,不同的事務(wù)隔離級別所表現(xiàn)出的不同特點,那么自然還是要先模擬一下并發(fā)環(huán)境
這里打開兩個獨立的mysql數(shù)據(jù)庫連接(mysql程序1和mysql程序2),用來模擬并發(fā)環(huán)境
咳咳咳… 正片開始
同志們打起精神認真看?。?!
- read uncommitted(讀未提交)
首先,我們需要先將兩個會話的事務(wù)隔離級別都設(shè)置為read uncommitted;語句如下:
read uncommitted可以讀到其他事務(wù)還沒提交的變更,這里舉例:程序2對t_account表中的數(shù)據(jù)進行更改,看程序1多次查詢的結(jié)果是否一致。
可以看到程序2改變了t_account表中的vname字段,將李二改為了張三。但是程序1呢,連續(xù)2個select查詢語句的結(jié)果竟然不一致,估計現(xiàn)在程序1的表情和你手機里的第三個表情包一樣。這就是read uncommitted隔離級別的特點。
不管你事務(wù)是否提交,只要數(shù)據(jù)發(fā)生改變我就可以察覺到…嘻嘻。是不是感覺它很強大。什么事情都逃不過它的法眼。
接下來要看的是read committed(讀已提交)
- read committed(讀已提交)
測試前一定要記住設(shè)置事務(wù)的隔離級別為read committed;并且禁用自動提交事務(wù)【設(shè)置autocommit為0】(后面的每個測試都是一樣的)
# 設(shè)置事務(wù)隔離級別為read committed set session transaction isolation level read committed; # 禁用自動提交事務(wù)功能 set autocommit = 0; #接下來的 repeatable read 隔離級別和 serializable 隔離級別也是同樣的操作
以上例子實現(xiàn)了王五為張三轉(zhuǎn)賬的事務(wù),可以看到程序2中事務(wù)提交前與提交后對程序1中的查詢語句產(chǎn)生的影響,前2個查詢是事務(wù)沒提交的結(jié)果,最后一個查詢是事務(wù)提交后的結(jié)果。 相信上面的例子已經(jīng)很充分的詮釋了read committed的特點。
- repeatable read(可重復(fù)讀)
該隔離級別為mysql的默認隔離級別;它對某字段進行操作時,其他事務(wù)禁止操作該字段。它總能保持你讀取的數(shù)據(jù)是一致的。
以下代碼中,程序1模擬"王五向張三轉(zhuǎn)賬30元",程序2則在程序1在處理事務(wù)時,對張三的余額進行清空處理
因為當前的事務(wù)隔離級別為repeatable read級別,所以在程序1操作t_account表時,程序2是無權(quán)對t_account表進行任何操作,如果強行操作的話,就會發(fā)生error (錯誤)
“ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction”;
其中文意思是:“超過鎖定等待超時;嘗試重新啟動事務(wù)”
只有當程序1對t_account表操作完成后(結(jié)束事務(wù)后),程序2才可以對t_account表進行操作。
- serializable(串行化)
該隔離模式下執(zhí)行的事務(wù)在對某表進行操作期間,禁止其他所有事務(wù)對該表進行任何操作
如果強行操作也會報錯(和上面那個錯誤一致),因為serializable用的相對比較少,這里就不做演示了。同學們理解了就好。
- 事務(wù)的保存點(回滾點)
回滾點表示的就是使事務(wù)回滾到指定回滾點
語法: savepoint 節(jié)點名稱 ;
注意:保存點只允許搭配rollback回滾來使用,不能和commit一起使用
已知表t_stu存在,其數(shù)據(jù)如下:
代碼舉例如下:
#禁用自動提交事務(wù) set autocommit = 0; #開啟事務(wù) start transaction; #刪除id為2的記錄 delete from t_stu where id = 2; #設(shè)置保存點名為AA savepoint AA; #刪除id為3的記錄 delete from t_stu where id = 3; #回滾到AA保存點處 rollback to AA;
運行結(jié)果如下:
可以看到id為2的李四被刪除了,而王五卻還在,就是因為事務(wù)回滾到了AA處,所以id為3的那條記錄被回滾掉了。
總結(jié)
到此這篇關(guān)于MySQL事務(wù)(transaction)的文章就介紹到這了,更多相關(guān)MySQL事務(wù)transaction內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mybatis mysql delete in操作只能刪除第一條數(shù)據(jù)的方法
這篇文章主要介紹了mybatis mysql delete in操作只能刪除第一條數(shù)據(jù)的問題及解決方法,需要的朋友可以參考下2018-09-09MYSQL事務(wù)教程之Yii2.0商戶提現(xiàn)功能
這篇文章主要給大家介紹了關(guān)于MYSQL事務(wù)教程之Yii2.0商戶提現(xiàn)功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-07-07