54、【數(shù)據(jù)庫技術(shù)】【MySQL】事務(wù)

1宏榕、概述

  • 事務(wù)(Transaction)拓诸,在數(shù)據(jù)庫領(lǐng)域中可以理解成對數(shù)據(jù)操作的一個執(zhí)行單元侵佃。

  • 事務(wù)是一個整體,由一條或者多條 SQL 語句組成奠支,這些 SQL 語句要么都執(zhí)行成功馋辈,要么都執(zhí)行失敗,只要有一條 SQL 出現(xiàn)異常胚宦,整個操作就會回滾首有,導(dǎo)致整個事務(wù)執(zhí)行失敗。

  • 事務(wù)所涉及的 SQL 語句都是 DML 即數(shù)據(jù)操縱語句枢劝,像純 DQL 這樣的不涉及事務(wù)井联。

  • DML 涉及到數(shù)據(jù)的修改(增、刪您旁、改)烙常,而在計算機(jī)領(lǐng)域中,無可避免地會遇到并發(fā)鹤盒、網(wǎng)絡(luò)傳輸等來自各個方面的各種問題蚕脏,如果處理不當(dāng)會導(dǎo)致數(shù)據(jù)庫中的數(shù)據(jù)出現(xiàn)偏差,帶來很多麻煩侦锯。用事務(wù)的形式組織這些 DML驼鞭,如果事務(wù)中的所有語句都準(zhǔn)確無誤執(zhí)行,提交事務(wù)即最終確認(rèn)對數(shù)據(jù)的修改尺碰;而一旦其中任何一個語句出現(xiàn)問題挣棕,不提交事務(wù)并且需要恢復(fù)原狀。DQL 是查詢亲桥,僅進(jìn)行查詢操作不涉及數(shù)據(jù)修改洛心,所以沒有必要以事務(wù)的形式組織純 DQL

  • 明確一點题篷,只是說在僅進(jìn)行查詢操作的情況下词身,不用涉及事務(wù)。而不是說事務(wù)中不能有查詢操作番枚!事務(wù)中可以有查詢操作法严,但是需涉及到相應(yīng)的 DML 操作!

  • 回滾:即在事務(wù)運行的過程中發(fā)生了某種故障葫笼,事務(wù)不能繼續(xù)執(zhí)行深啤,將事務(wù)中對數(shù)據(jù)庫的所有已完成的操作全部撤銷,滾回到事務(wù)開始時的狀態(tài)渔欢。(在提交之前執(zhí)行)

2墓塌、事務(wù)的典型案例

  • 講數(shù)據(jù)庫的事務(wù)瘟忱,最經(jīng)典的案例就是銀行賬戶轉(zhuǎn)賬奥额。

  • 有兩個銀行賬戶分別是 A 和 B苫幢,其中 A 賬戶中有1000元,B 賬戶中有200元垫挨,A 賬戶需向 B 賬戶轉(zhuǎn)賬300元韩肝。

  • 假設(shè)銀行的數(shù)據(jù)庫用如下表存儲賬戶的金額信息:

CREATE TABLE tb (
id VARCHAR(10) PRIMARY KEY,
salary INT NOT NULL);

INSERT INTO tb (id,salary)
VALUES ('A',1000),('B',200);
  • 進(jìn)行轉(zhuǎn)賬,對應(yīng)數(shù)據(jù)庫應(yīng)執(zhí)行的 SQL 語句:
-- 語句1
UPDATE tb
SET salary=salary-300
WHERE id='A';

-- 語句2
UPDATE tb
SET salary=salary+300
WHERE id='B';

針對上述的語句1和語句2九榔,如果兩個都正確執(zhí)行了哀峻,沒有問題;但是如果語句1或語句2中的任何一個語句在執(zhí)行過程中出現(xiàn)差錯哲泊,比如說剩蟀,成功執(zhí)行語句1后,因為網(wǎng)絡(luò)連接出現(xiàn)問題切威,語句2沒有成功執(zhí)行育特,最終,賬戶 B 沒有收到轉(zhuǎn)賬且賬戶 A 中還少了300元先朦。這樣的話缰冤,直接導(dǎo)致現(xiàn)實中的經(jīng)濟(jì)損失。所以喳魏,需要以數(shù)據(jù)庫的事務(wù)來組織上面的兩個 SQL 語句棉浸,一旦出現(xiàn)問題,終止事務(wù)刺彩,及時回滾迷郑,恢復(fù)原狀。

3迂苛、MySQL 中事務(wù)自動提交

  • MySQL 默認(rèn)將一條 DML 語句就作為一個事務(wù)看待三热,并且自動提交即自動確認(rèn)生效。

  • MySQL 中查看配置自動提交的變量:

SHOW VARIABLES LIKE 'autocommit';
MySQL-默認(rèn)事務(wù)自動提交-ON 表示自動提交是開啟的
  • 將默認(rèn)自動提交設(shè)置為手動提交:
SET @@autocommit=OFF;

一旦經(jīng)過了上面的設(shè)置后三幻,如果希望執(zhí)行的 DML 語句生效就必須使用COMMIT來手動提交事務(wù)就漾。

4、MySQL 中事務(wù)手動提交

  • 在沒有將autocommit設(shè)置為OFF之前念搬,也可以手動提交事務(wù)抑堡,前提是需要顯式開啟事務(wù)

  • 開啟事務(wù)之后朗徊,其后面執(zhí)行的所有 DML 語句都不會立即生效首妖,直到提交事務(wù);如果出現(xiàn)問題爷恳,回滾事務(wù)有缆,恢復(fù)到開啟事務(wù)前的狀態(tài)。也就是說,事務(wù)的結(jié)局有兩種棚壁,要么被提交杯矩,要么被撤銷(回滾)即COMMITROLLBACK二選一。

MySQL-事務(wù)的結(jié)局
-- 顯式開啟一個事務(wù)
-- 這個語句顯式地標(biāo)記一個事務(wù)的起始點
START TRANSACTION;
-- 或者直接使用
BEGIN;

-- DML
······

-- 表示提交事務(wù)袖外,即提交事務(wù)的所有操作使前面所有的 DML 生效史隆,具體地說,就是將事務(wù)中所有對數(shù)據(jù)庫的更新都寫到物理的磁盤上中曼验,事務(wù)正常結(jié)束泌射。
COMMIT;

-- 表示撤銷(回滾)事務(wù),即在事務(wù)運行的過程中發(fā)生了某種故障鬓照,事務(wù)不能繼續(xù)執(zhí)行熔酷,系統(tǒng)將事務(wù)中對數(shù)據(jù)庫的所有已完成的操作全部撤銷,回滾到事務(wù)開始之前的狀態(tài)豺裆。
ROLLBACK纯陨;
  • 舉例:轉(zhuǎn)賬
CREATE TABLE my_tb1 (
id CHAR(1) PRIMARY KEY,
salary INT NOT NULL DEFAULT 0
);

INSERT INTO my_tb1 (id,salary)
VALUES ('A',1000),('B',300);
-- 事務(wù)成功,提交

START TRANSACTION;

UPDATE my_tb1
SET salary=salary-200
WHERE id='A';

UPDATE my_tb1
SET salary=salary+200
WHERE id='B';

COMMIT;
-- 事務(wù)失敗留储,回滾

START TRANSACTION;

UPDATE my_tb1
SET salary=salary-200
WHERE id='A';

UPDATE my_tb1
SET salary=salary+200
WHERE id='B';

ROLLBACK;

5翼抠、事務(wù)的特性

MySQL-事務(wù)的特性

6、MySQL 事務(wù)隔離級別

  • 根據(jù)事務(wù)的隔離性获讳,各個事務(wù)之間是相互獨立的阴颖,但是現(xiàn)實中往往會因為并發(fā)訪問等因素導(dǎo)致“隔離”出現(xiàn)問題,這個時候可以通過設(shè)置隔離級別來解決這些問題丐膝。

  • 關(guān)于并發(fā)訪問等帶來的問題量愧,并不是僅在數(shù)據(jù)庫層面就能解決的;同樣的道理帅矗,在數(shù)據(jù)庫層面偎肃,也并不是只有設(shè)置隔離級別這一種方式解決問題

  • 并發(fā)訪問帶來的問題:

1浑此、臟讀:讀取到涉及未提交事務(wù)的數(shù)據(jù)累颂。讀取到的數(shù)據(jù)稱為“臟數(shù)據(jù)”。
比如:賬戶 A 向 賬戶 B 轉(zhuǎn)賬500元凛俱,賬戶 B 讀取到自己的賬戶余額中有500元紊馏,當(dāng) B 想用這些錢去購物結(jié)賬的時候,出現(xiàn)問題蒲犬,導(dǎo)致“轉(zhuǎn)賬”事務(wù)回滾朱监,此時 B 再次查看賬戶的時候,這500元沒有了原叮。

2赫编、不可重復(fù)讀:在一個事務(wù)中(大前提巡蘸,在一個事務(wù)中),對同一個數(shù)據(jù)擂送,多次讀取的結(jié)果不一致赡若。

3、幻讀:在一個事務(wù)中团甲,雖然是基于查詢到的結(jié)果設(shè)計并執(zhí)行 DML 但是出現(xiàn)問題,也就是查詢出的結(jié)果無法支撐后續(xù)的操作黍聂。
比如:希望通過一個事務(wù)向表中插入一條數(shù)據(jù)躺苦,查詢到表中沒有與之重復(fù)的數(shù)據(jù),但是執(zhí)行插入操作的時候产还,卻發(fā)現(xiàn)該數(shù)據(jù)已經(jīng)存在匹厘。

  • MySQL 中事務(wù)隔離級別(由低到高):

最低級別:讀未提交(read uncommitted)
解釋:進(jìn)行查詢操作,未提交事務(wù)引發(fā)的數(shù)據(jù)修改的結(jié)果也能被查詢到脐区。
能規(guī)避的問題:無法規(guī)避任何一種問題

讀已提交(read committed)
解釋:進(jìn)行查詢操作愈诚,未提交事務(wù)引發(fā)的數(shù)據(jù)修改的結(jié)果不能被查詢到,只能查詢到已提交事務(wù)引發(fā)的數(shù)據(jù)修改的結(jié)果牛隅。
能規(guī)避的問題:臟讀
備注:Oracle 數(shù)據(jù)庫炕柔、Microsoft SQL Server 數(shù)據(jù)庫默認(rèn)使用的隔離級別。

可重復(fù)讀(repeatable read)
解釋:在“讀已提交”的基礎(chǔ)上媒佣,
能規(guī)避的問題:臟讀匕累、不可重復(fù)讀
備注:MySQL 數(shù)據(jù)庫默認(rèn)使用的隔離級別

最高級別:串行化(serializable)
解釋:
能規(guī)避的問題:臟讀、不可重復(fù)讀默伍、幻讀

MySQL-事務(wù)隔離級別
  • 事務(wù)隔離級別越高欢嘿,能夠規(guī)避的問題越多,數(shù)據(jù)的安全性越強(qiáng)但是讀寫效率會隨之降低也糊。需結(jié)合實際情況選擇合適的隔離級別炼蹦。另外,由并發(fā)帶來的問題狸剃,不僅僅需要在數(shù)據(jù)庫層面解決掐隐,在數(shù)據(jù)庫層面,也不只有隔離級別這一種解決方案钞馁。

6.1瑟枫、MySQL 查看與修改事務(wù)隔離級別

  • 查看隔離級別

MySQL 中有兩類事務(wù)隔離級別,一類是全局事務(wù)隔離級別指攒,一類是當(dāng)前會話事務(wù)隔離級別慷妙。
全局事務(wù)隔離級別:對所有會話都生效;
當(dāng)前會話事務(wù)隔離級別:只對當(dāng)前會話有效允悦;

會話:與 MySQL 服務(wù)建立一個連接稱為一個會話膝擂。

-- 查看全局事務(wù)隔離級別
SELECT  @@global.transaction_isolation;

-- 查看當(dāng)前會話事務(wù)隔離級別
SELECT @@transaction_isolation;
SELECT @@session.transaction_isolation;

-- 查看全局事務(wù)隔離級別
-- MySQL 8.0 版本無法使用虑啤,提示沒有這個值
SELECT @@global.tx_isolation;

-- 查看當(dāng)前會話事務(wù)隔離級別
-- MySQL 8.0 版本無法使用,提示沒有這個值
SELECT @@tx_isolation;
SELECT @@session.tx_isolation;
MySQL-默認(rèn)的事務(wù)隔離級別
  • 修改事務(wù)隔離級別
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

6.2架馋、“臟讀”演示

  • 為了演示“臟讀”現(xiàn)象狞山,先將 MySQL 全局的事務(wù)隔離級別調(diào)整至READ UNCOMMITTED
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
  • 仍以轉(zhuǎn)賬為例叉寂。新(修改完隔離級別后必須重新建立會話才有效)打開兩個命令行窗口即兩個會話萍启,來模擬一種并發(fā)場景,一個稱為Session 1屏鳍,另一個稱為Session 2勘纯。

1、在Session 2中開啟一個事務(wù)钓瞭,執(zhí)行“轉(zhuǎn)賬”操作驳遵,暫不提交:

MySQL-臟讀演示1

2、此時山涡,在Session 1中執(zhí)行查詢操作堤结,查詢結(jié)果如下:

MySQL-臟讀演示2

可以看到,未提交的事務(wù)引起的數(shù)據(jù)變化也會被查詢到鸭丛。如果Session 2最終提交了事務(wù)竞穷,也沒什么影響,但是如果Session 2因某種原因必須回滾事務(wù)并且Session 1也沒有重新查詢確認(rèn)鳞溉,此時Session 1出現(xiàn)的問題就是“臟讀”来庭,即讀到了“臟數(shù)據(jù)”。

6.3穿挨、“不可重復(fù)讀”演示

  • 為了演示“不可重復(fù)讀”現(xiàn)象月弛,先將 MySQL 全局的事務(wù)隔離級別調(diào)整至READ UNCOMMITTEDREAD COMMITTED
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • 仍以轉(zhuǎn)賬為例科盛。新打開兩個命令行窗口即兩個會話帽衙,來模擬一種并發(fā)場景,一個稱為Session 1贞绵,另一個稱為Session 2厉萝。

1、在Session 2中開啟事務(wù)榨崩,先執(zhí)行一次查詢:

MySQL-不可重復(fù)讀演示1

2谴垫、在Session 1中開啟事務(wù),執(zhí)行“轉(zhuǎn)賬”母蛛,并提交:

MySQL-不可重復(fù)讀演示2

3翩剪、在Session 2中已開啟的事務(wù)中再次執(zhí)行查詢:

MySQL-不可重復(fù)讀演示3

在同一個事務(wù)中,讀取到的數(shù)據(jù)不一樣彩郊,這就是“不可重復(fù)讀”前弯,可能會感到奇怪蚪缀,查詢到不一樣的不是很正常的嗎,在下面會按照上面的步驟演示“可重復(fù)讀”恕出。

  • 演示“可重復(fù)讀”询枚,首先將事務(wù)隔離等級調(diào)整至REPEATABLE READSERIALIZABLE,規(guī)避“不可重復(fù)讀”浙巫。下面與“不可重復(fù)讀”步驟一樣:
MySQL-可重復(fù)讀演示1
MySQL-可重復(fù)讀演示2
MySQL-可重復(fù)讀演示3
MySQL-可重復(fù)讀演示4

可重復(fù)讀:在一個事務(wù)中(大前提金蜀,在一個事務(wù)中),對同一個數(shù)據(jù)的畴,多次讀取的結(jié)果一致渊抄。

6.4、“幻讀”演示

  • 演示“幻讀”苗傅,首先將事務(wù)隔離等級調(diào)整至READ UNCOMMITTEDREAD COMMITTEDREPEATABLE READ

  • 以添加賬戶為例班巩。新打開兩個命令行窗口即兩個會話渣慕,來模擬一種并發(fā)場景,一個稱為Session 1抱慌,另一個稱為Session 2逊桦。

1、在Session 1Session 2中均開啟事務(wù)抑进。
2强经、Session 1準(zhǔn)備向賬戶中添加一個id(主鍵)為 C 的賬戶,所以寺渗,先查詢一下是否存在id為 C 的賬戶匿情。

MySQL-幻讀演示1

3、Session 2Session 1通過查詢確定后要插入數(shù)據(jù)之前信殊,插入了一個id為 C 的數(shù)據(jù)炬称,并提交事務(wù)。

MySQL-幻讀演示2

4涡拘、等Session 1在插入數(shù)據(jù)時玲躯,發(fā)現(xiàn)出現(xiàn)錯誤,無法將數(shù)據(jù)插入鳄乏。

MySQL-幻讀演示3

避免幻讀跷车,需要將隔離級別提升到最高的SERIALIZABLE。一旦提示到這個級別橱野,意味著朽缴,在一個事務(wù)中執(zhí)行 DML 但未COMMIT或未ROLLBACK的時候,其他事務(wù)進(jìn)行的所有操作(包括查詢)都將被“阻塞”水援,直到那個事務(wù)執(zhí)行了COMMITROLLBACK不铆。
SERIALIZABLE級別基本上是不去使用的蝌焚,因為效率太低。還是那句話誓斥,因并發(fā)導(dǎo)致的問題只洒,不應(yīng)只在數(shù)據(jù)庫層面解決,即使在數(shù)據(jù)庫層面劳坑,也不止設(shè)置隔離級別這一種方案毕谴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市距芬,隨后出現(xiàn)的幾起案子涝开,更是在濱河造成了極大的恐慌,老刑警劉巖框仔,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舀武,死亡現(xiàn)場離奇詭異,居然都是意外死亡离斩,警方通過查閱死者的電腦和手機(jī)银舱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跛梗,“玉大人寻馏,你說我怎么就攤上這事『顺ィ” “怎么了诚欠?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長漾岳。 經(jīng)常有香客問我轰绵,道長,這世上最難降的妖魔是什么尼荆? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任藏澳,我火速辦了婚禮,結(jié)果婚禮上耀找,老公的妹妹穿的比我還像新娘翔悠。我一直安慰自己,他們只是感情好野芒,可當(dāng)我...
    茶點故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布蓄愁。 她就那樣靜靜地躺著,像睡著了一般狞悲。 火紅的嫁衣襯著肌膚如雪撮抓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天摇锋,我揣著相機(jī)與錄音丹拯,去河邊找鬼站超。 笑死,一個胖子當(dāng)著我的面吹牛乖酬,可吹牛的內(nèi)容都是我干的死相。 我是一名探鬼主播,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼咬像,長吁一口氣:“原來是場噩夢啊……” “哼算撮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起县昂,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤肮柜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后倒彰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體审洞,經(jīng)...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年待讳,在試婚紗的時候發(fā)現(xiàn)自己被綠了芒澜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,697評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡耙箍,死狀恐怖撰糠,靈堂內(nèi)的尸體忽然破棺而出痴突,到底是詐尸還是另有隱情具练,我是刑警寧澤蛋济,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布,位于F島的核電站汁针,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏砚尽。R本人自食惡果不足惜施无,卻給世界環(huán)境...
    茶點故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望必孤。 院中可真熱鬧猾骡,春花似錦、人聲如沸敷搪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赡勘。三九已至嫂便,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間闸与,已是汗流浹背毙替。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工岸售, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厂画。 一個月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓凸丸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親木羹。 傳聞我的和親對象是個殘疾皇子甲雅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,587評論 2 350

推薦閱讀更多精彩內(nèi)容