日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

MySQL中的事务

發布時間:2024/8/26 综合教程 34 生活家
生活随笔 收集整理的這篇文章主要介紹了 MySQL中的事务 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

秋招告一段落,浪了好久也該總結總結了,雖然面試這一類別下絕大部分都是參考的別的博客,但自己再整理一遍總感覺印象更深吧。對于參考的原文都有表明原文鏈接

-----------------------------------------------------------------------------------------------

轉自:https://www.cnblogs.com/hebao0514/category/719525.html

一、事務的四大特性(ACID)

1. 原子性(atomicity):一個事務必須視為一個不可分割的最小工作單元,整個事務中的所有操作要么全部提交成功,要么全部失敗回滾,對于一個事務來說,不可能只執行其中的一部分操作,這就是事務的原子性。

2. 一致性(consistency):數據庫總是從一個一致性的狀態轉換到另一個一致性的狀態。
拿轉賬來說,假設用戶A和用戶B兩者的錢加起來一共是5000,那么不管A和B之間如何轉賬,轉幾次賬,事務結束后兩個用戶的錢相加起來應該還得是5000,這就是事務的一致性。

3. 隔離性(isolation):一個事務所做的修改在最終提交以前,對其他事務是不可見的。
比如操作同一張表時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作所干擾,多個并發事務之間要相互隔離。

4. 持久性(durability):一旦事務提交,則其所做的修改就會永久保存到數據庫中。此時即使系統崩潰,修改的數據也不會丟失。

二、事務的簡單使用
1. 在使用數據庫時候需要使用事務,必須先開啟事務,開啟事務的語句具體如下:

start transaction;

2. 事務開啟之后就可以執行SQL語句
3. SQL語句執行成功之后,需要提交事務,提交事務的語句如下:

commit;

note:
在MySQL中直接書寫的SQL語句都是自動提交的,而事務中的操作語句需要使用commit語句手動提交,只有事務提交后其中的操作才會生效。
如果不想提交事務,我們還可以使用相關語句取消事務(也稱回滾),具體語句如下:

rollback;

需要注意的是,rollback語句只能針對未提交的事務執行的回滾操作,已經提交的事務是不能回滾的。

例子:通過一個轉賬的案例演示如何使用事務。
1. 創建表

create table account(
    id int primary key auto_increment,
    name varchar(40),
    money float
);
insert into account(name,money) values('a',1000);
insert into account(name,money) values('b',1000);

2. 使用事務來實現轉賬:首先開啟一個事務,然后通過update語句將 a賬戶的100元 轉給 b 賬戶,然后提交事務

start transaction;
update account set money=money-100 where name='a';
update account set money=money+100 where name='b';
commit;

1). 在命令行中執行,執行效果如下:

事務提交和事務回滾的具體例子參考這里:事務提交、事務回滾

2). 在Navicat中執行,執行結果如下:

參考:

https://www.cnblogs.com/hebao0514/p/5490698.html

三、臟讀

(一)、什么是臟讀

臟讀就是指一個事務讀取了另一個事務未提交的數據。

(二)、臟讀的例子及避免

(1). 臟讀例子:

臟讀例子:https://www.cnblogs.com/hebao0514/p/5490764.htmlRead Uncommitted(讀未提交)(個人理解:一個事務讀到另一個事務還未提交的數據)

例子說明:開啟兩個線程,分別模擬a賬戶和b賬戶,
MySQL的默認隔離級別是Repeatable Read(可重復讀),該級別是可以避免臟讀的,因此需要將b賬戶中事務的隔離級別設置為Read Uncommitted(讀未提交)。
在a賬戶中開啟一個事務,執行轉賬功能,但未提交(commit);在b賬戶中開啟一個事務,執行查詢功能,因為b賬戶的事務隔離級別低,
就讀到了a賬戶還沒提交的數據(即出現臟讀),這時候,b誤以為a賬戶已經轉賬成功,便會給a發貨,當b發貨之后,a如果不提交事務而將事務回滾,b就會受到損失。

(2). 避免臟讀:Read Committed 隔離級別來避免臟讀的例子:

1. a賬戶(左)和b賬戶(右)當前余額:

2. 開啟事務,轉賬給b賬戶:

3. 此時a賬戶的事務并未提交,此時b賬戶查看余額:

可以看出,b賬戶中仍為1000,沒有讀到a賬戶中沒有提交的信息。說明Read Committed 隔離級別可以避免臟讀

四、事務隔離級別

https://www.cnblogs.com/hebao0514/p/5492108.html

1). Read Uncommitted   2). Read Committed   3). Repeatable Read   4). Serializable
(1)Read Uncommitted
Read UnCommitted(讀未提交)是事務中最低的級別,該級別下的事務可以讀取到另一個事務中未提交的數據,也被稱為臟讀(Dirty Read),這是相當危險的。由于該級別較低,在實際開發中避免不了任何情況,所以一般很少使用。

(2)Read Committed
大多數的數據庫管理系統的默認隔離級別都是Read Committed(讀提交),該級別下的事務只能讀取其他事務中已經提交的內容,可以避免臟讀,但是不能避免重復讀和幻讀的情況。
重復讀:在事務內讀取了別的線程已經提交的數據,但是兩次查詢讀取結果不一樣,原因是查詢的過程中其他事務做了更新操作
幻讀:在事務內兩次查詢的數據條數不一樣,原因是查詢的過程中其他事務做了添加操作

(3)Repeatable Read
Repeatable Read(可重復讀)是MySQL默認的事務隔離級別,它可以避免臟讀、不可重復讀的問題,確保同一個事務的多個實例在并發操作數據的時候,會看到相同的數據行。但是理論上,該級別會出現幻讀情況,不過MySQL的存儲引擎通過多版本并發控制機制解決了該問題,因此該級別是可以避免幻讀的。

(4)Serializable
Serializable(可串行化)是事務的最高隔離級別,它會強制對事務進行排序,使它們彼此之間不會發生沖突,從而解決臟讀、幻讀、重復讀的問題。實際上,就是在每個讀的數據行上加上鎖。這個級別,可能導致大量超時現象和鎖競爭,實際應用中很少使用。

五、不可重復讀

(一)、什么是不可重復讀

不可重復讀(Non-Repeatable Read)是指事務中兩次查詢的結果不一致,原因是在查詢的過程中其他事務做了更新的操作。

例如,銀行在做統計報表的時候,第一次查詢a賬戶有1000元,第二次查詢a賬戶有900元,原因是統計期間a賬戶取出了100元,這樣導致多次查詢中,查詢結果不一致。

不可重復讀和臟讀有點類似,但是臟讀是讀取了另一個事務未提交的臟數據,不可重復讀是在事務內重復讀取了別的線程已提交的數據。

note:MySQL的默認事務隔離級別是:Repeatable Read(可重復讀)

(二)、不可重復讀的例子及避免

(1). 不可重復讀的例子

不可重復讀的例子:https://www.cnblogs.com/hebao0514/p/5494442.html Repeatable Read(可重復讀)(個人理解:一個事務中,重復查詢的結果是一樣的,哪怕在第一次查詢之后,數據庫已經變了,查詢結果仍與第一次查詢結果一致,而不是查詢數據庫中的最新數據)

1. 線程2:查看線程2中事務隔離級別:

1. 線程2:首先在線程2中開啟一個事務,然后在當前事務中查詢各個賬戶的余額信息:

3. 線程1:線程1中不用開啟事務,直接使用update更新a賬戶,并查詢余額:

note:由于線程1只需要執行修改的操作,不需要保證同步性,因此直接執行SQL語句就可以
4. 線程2:當線程1更新操作執行完成后,在線程2中再次查詢各賬戶余額,發現a賬戶變為900:

線程2中,a賬戶兩次的查詢結果不一致,實際上這種操作是沒有錯的(雖然沒錯,但應該避免這種情況?)

例子說明:開啟兩個線程1和2,線程2的隔離級別為Read Committed。在線程2中開啟事務,查詢a賬戶為1000,此時還不提交事務;在線程1中不用開啟事務,更新a賬務為900;返回線程2(此時事務還沒有提交),查詢a賬戶變為900。即:線程2在同一個事務中,兩次查詢結果不一致。(博客例子中的a賬戶和b賬戶應該為表述錯誤,應為:線程1和線程2,操作的賬戶都是a賬戶。另外博客的線程2(即b賬戶中)繼前一篇博客的操作,已經改成了Read Committed 隔離級別)

(2).避免不可重復讀:Repeatable Read隔離級別來避免不可重復讀的例子:

1. 查看線程1中事務隔離級別:

2. 在線程1中開啟一個事務,然后在當前事務中查詢各個賬戶的余額信息:

3. 線程2中不用開啟事務,直接使用update語句執行更新操作,并查詢余額:

4. 返回線程1:當線程2更新操作執行完成后,在線程1中再次查詢賬戶余額,發現a賬戶仍未1000:

5. 如果此時在線程1中修改a賬戶,會報錯:ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

六、幻讀

(一)、什么是幻讀

幻讀(Phantom Read)又稱為虛讀,是指在一個事務內兩次查詢中數據條數不一致,幻讀和不重復讀有些不同,同樣是在兩次查詢過程中,不同的是,幻讀是由于其他事務做了插入記錄的操作,導致記錄數有所增加。

例如:銀行在做統計報表時統計account表中所有用戶的總金額時候,此時總共有兩個賬戶,總共金額為2000元,這時候新增了一個用戶賬戶,并且存入1000元,這時候銀行再次統計就會發現賬戶總金額為3000,造成了幻讀情況

(二)、幻讀的例子及避免

(1). 幻讀的例子

幻讀的例子:https://www.cnblogs.com/hebao0514/p/5494588.html Phantom Read(幻讀、虛讀)(個人理解:一個事務中,重復查詢的結果是一樣的,哪怕在第一次查詢之后,數據庫已經變了,查詢結果仍與第一次查詢結果一致,而不是查詢數據庫中的最新數據。幻讀是針對insert操作)

1. 線程2:首先設置線程2的隔離級別為Read Committed,并查詢。(可重復讀隔離級別是可以避免幻讀的出現,因此需要將事務的隔離級別設置為更低)

2. 線程2:開啟一個事務,然后在當前事務中查詢賬戶的余額信息:

3. 線程1:先查詢account表中的信息,然后進行添加操作:(線程1不用開啟事務,直接執行添加操作即可)

4. 線程2:線程1添加完記錄后,在線程2中查詢余額信息:

可以發現,在Read Committed隔離級別下,線程2中第二次查詢數據比第一查詢數據的時候多一條記錄,這種情況并不是錯誤的,但可能不符合實際需求。

例子說明:開啟兩個線程1和2,線程2的隔離級別為Read Committed。在線程2中開啟事務,查詢account表的結果為共有兩條記錄;在線程1中不用開啟事務,在線程1中添加一條記錄(c,1000);返回線程2,查詢account表,查詢結果變為共有三條記錄。即:線程2在同一個事務中,兩次查詢結果不一致。

幻讀和不重復讀的區別:
同樣在兩次查詢過程中,不同的是,幻讀是由于其他事務做了插入操作(insert),導致記錄數有所增加。而不重復讀是由于其他事務做了更新操作(update),導致同一條記錄的查詢結果不同。

(2).避免幻讀:Repeatable Read隔離級別來避免幻讀的例子:

先刪除剛才添加的(c,1000)這一條記錄

1. 線程2:為了防止出現幻讀,可以將線程2的隔離級別設置為Repeatable Read

2. 線程2:開啟一個事務,然后在當前事務中查詢賬戶的余額信息:

3. 線程1:先查詢account表中的信息,然后進行添加操作:(線程1不用開啟事務,直接執行添加操作即可)

4. 線程2:線程1添加完記錄后,在線程2中查詢余額信息

可以發現,在Repeatable Read隔離級別下,線程2中兩次查詢結果是一樣的。
5. 線程2:使用commit提交當前事務,再查詢account表,查詢到三條記錄

Repeatable Read從理論的角度是會出現幻讀的,但是MySQL內部通過多版本控制機制【實際上就是對讀取到的數據加鎖】解決這個問題。
因此,用戶才可以放心大膽使用Repeatable Read這個事務隔離級別。

note:Serializable 和 Repeatable Read都可以防止幻讀。但是Serializable 事務隔離級別效率低下,比較耗數據庫性能,一般不使用。

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。