一文精通MySQL事務(wù)規(guī)則
點擊上方“框架師”,選擇“置頂公眾號”
我們一起學(xué)習(xí)進步!


引言:
每個程序員學(xué)習(xí)數(shù)據(jù)庫離不開MySQL,而學(xué)習(xí)MySQL就必學(xué)事務(wù),今天我們就來一起學(xué)習(xí)一下MySQL的事務(wù);
事務(wù)的概念
在實際的業(yè)務(wù)開發(fā)中,有些業(yè)務(wù)操作要多次訪問數(shù)據(jù)庫。一個業(yè)務(wù)要發(fā)送多條SQL語句給數(shù)據(jù)庫執(zhí)行。由多條SQL語句組成一個功能(事務(wù)).需要將多次訪問數(shù)據(jù)庫的操作視為一個整體來執(zhí)行,要么所有的SQL語句全部執(zhí)行成功。如果其中有一條SQL語句失敗,就進行事務(wù)的回滾,所有的SQL語句全部執(zhí)行失敗。
事務(wù)應(yīng)用場景
最通俗易懂的就是銀行轉(zhuǎn)賬的案例,例如張三給李四轉(zhuǎn)錢,張三賬號減去相應(yīng)數(shù)額資金,李四賬號添加相應(yīng)數(shù)額資金;
案例演示:
-- 創(chuàng)建account數(shù)據(jù)表
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加數(shù)據(jù)
INSERT INTO account (NAME, balance) VALUES ('張三', 1000), ('李四', 1000);模擬張三給李四轉(zhuǎn)500元錢,一個轉(zhuǎn)賬的業(yè)務(wù)操作最少要執(zhí)行下面的2條sql語句:
張三賬號-500
-- 1. 張三賬號-500
UPDATE account SET balance = balance - 500 WHERE id=1;李四賬號+500
-- 2. 李四賬號+500
UPDATE account SET balance = balance + 500 WHERE id=2;結(jié)果如下

假設(shè)當張三賬號上-500元,服務(wù)器崩潰了。李四的賬號并沒有+500元,數(shù)據(jù)就出現(xiàn)問題了。我們需要保證其中一條SQL語句出現(xiàn)問題,整個轉(zhuǎn)賬就算失敗。只有兩條SQL都成功了轉(zhuǎn)賬才算成功。這個時候就需要用到事務(wù)。
事務(wù)的四大特性(A,C,I,D)
| 事務(wù)特性 | 描述 |
| 原子性(Atomicity) | 事務(wù)是一個不可分割的工作單位,事務(wù)中的操作要么都發(fā)生,要么都不發(fā)生 |
| 一致性(Consistency) | 事務(wù)前后數(shù)據(jù)的完整性必須保持一致 |
| 隔離性(Isolation) | 如多個用戶并發(fā)訪問數(shù)據(jù)庫時,一個用戶的事務(wù)不可以被其它用戶的事務(wù)所干擾,多個用戶并發(fā)事務(wù)之間數(shù)據(jù)要相互隔離,不可以互相影響 |
| 持久性(Durability) | 如一個事務(wù)一旦被提交,它對數(shù)據(jù)庫中的數(shù)據(jù)改變就是永久性的,就算未來數(shù)據(jù)庫發(fā)生故障也不應(yīng)該對數(shù)據(jù)有所影響 |
手動提交事務(wù)
在MySQL數(shù)據(jù)庫中有兩種提交事務(wù)的規(guī)則,一種是手動提交事務(wù),一種是自動提交事務(wù),其中自動提交事務(wù)是默認的,下面先看一下手動提交事務(wù)的案例,MySQL中有專門用于事務(wù)的SQL,如下
| SQL | 描述 |
| start transaction | 開始事務(wù) |
| commit | 提交事務(wù) |
| rollback | 回滾事務(wù) |
| End Transaction | 事務(wù)結(jié)束 |
手動提交事務(wù)步驟
?手動提交事務(wù)分別有兩種情況,如下圖

第1種情況:開啟事務(wù) -> 執(zhí)行SQL語句 -> 成功 -> 提交事務(wù)
目前數(shù)據(jù)庫內(nèi)容如下

使用DOS控制臺進入MySQL
執(zhí)行以下SQL語句:1.開啟事務(wù), 2.張三賬號-500, 3.李四賬號+500
START TRANSACTION;
UPDATE account SET balance = balance - 500 WHERE id=1;
UPDATE account SET balance = balance + 500 WHERE id=2;

使用Navicat查看數(shù)據(jù)庫數(shù)據(jù),發(fā)現(xiàn)數(shù)據(jù)庫并沒有變

在控制臺執(zhí)行
commit提交任務(wù):

使用Navicat查看數(shù)據(jù)庫:發(fā)現(xiàn)數(shù)據(jù)改變

第2種情況:開啟事務(wù) -> 執(zhí)行SQL語句 -> 失敗 -> 回滾事務(wù)
模擬張三給李四轉(zhuǎn)500元錢(失?。┠壳皵?shù)據(jù)庫數(shù)據(jù)如下:

在控制臺執(zhí)行以下SQL語句:1.開啟事務(wù), 2.張三賬號-500
START TRANSACTION;
UPDATE account SET balance = balance - 500 WHERE id=1;
使用Navicat查看數(shù)據(jù)庫:發(fā)現(xiàn)數(shù)據(jù)并沒有改變

在控制臺執(zhí)行rollback回滾事務(wù):

使用Navicat查看數(shù)據(jù)庫:發(fā)現(xiàn)數(shù)據(jù)沒有改變

自動提交事務(wù)
MySQL的每一條DML(增刪改)語句都是一個單獨的事務(wù),每條語句都會自動開啟一個事務(wù),執(zhí)行完畢自動提交事務(wù),MySQL默認開始自動提交事務(wù)。
將張三和李四金額重置為1000

執(zhí)行以下SQL語句
UPDATE account SET balance = balance - 500 WHERE id=1;
使用Navicat查看數(shù)據(jù)庫:發(fā)現(xiàn)數(shù)據(jù)已經(jīng)改變

?我們可以使用SQL語句查看MySQL是否開啟自動提交事務(wù)
show variables like '%commit%';
-- 或
SELECT @@autocommit;
通過修改MySQL全局變量"autocommit",取消自動提交事務(wù)

0:OFF(關(guān)閉自動提交)
1:ON(開啟自動提交)
取消自動提交事務(wù),設(shè)置自動提交的參數(shù)為OFF,執(zhí)行SQL語句:set autocommit = 0;

在控制臺執(zhí)行以下SQL語句:張三-500
UPDATE account SET balance = balance - 500 WHERE id=1;
使用Navicat查看數(shù)據(jù)庫,發(fā)現(xiàn)數(shù)據(jù)并沒有改變

在控制臺執(zhí)行commit提交任務(wù)

使用Navicat查看數(shù)據(jù)庫,發(fā)現(xiàn)數(shù)據(jù)改變

MySQL事務(wù)的原理
事務(wù)開啟之后, 所有的操作都會臨時保存到事務(wù)日志, 事務(wù)日志只有在得到commit命令才會同步到數(shù)據(jù)表中,其他任何情況都會清空事務(wù)日志(rollback,斷開連接),如下圖

事務(wù)的隔離級別
事務(wù)在操作時的理想狀態(tài):多個事務(wù)之間互不影響,如果隔離級別設(shè)置不當就可能引發(fā)并發(fā)訪問問題。
| 并發(fā)訪問的問題 | 含義 |
| 臟讀 | 一個事務(wù)讀取到了另一個事務(wù)尚未提交的數(shù)據(jù) |
| 不可重復(fù)讀 | 一個事務(wù)中兩次讀取的數(shù)據(jù)內(nèi)容不一致 |
| 幻讀 | 一個事務(wù)讀取到了別的事務(wù)插入的數(shù)據(jù),導(dǎo)致前后讀取記錄行數(shù)不同 |
臟讀演示

不可重復(fù)讀演示

幻讀演示

MySQL數(shù)據(jù)庫有四種隔離級別:上面的級別最低,下面的級別最高。“是”表示會出現(xiàn)這種問題,“否”表示不會出現(xiàn)這種問題。
| 級別 | 名稱 | 隔離級別 | 臟讀 | 不可重復(fù)讀 | 幻讀 | 數(shù)據(jù)庫默認隔離級別 |
| 1 | 讀未提交 | read uncommitted | 是 | 是 | 是 | |
| 2 | 讀已提交 | read committed | 否 | 是 | 是 | Oracle和SQL Server |
| 3 | 可重復(fù)讀 | repeatable read | 否 | 否 | 是 | MySQL |
| 4 | 串行化 | serializable | 否 | 否 | 否 |

下面給大家推薦幾篇之前的文章,之前有小伙伴問我要過博客源碼,現(xiàn)在已經(jīng)將源碼開源在碼云了,需要的小伙伴點擊閱讀原文進入我博客找零基礎(chǔ)搭建博客那篇文章,首條就是碼云地址,如果這篇文章有幫助到你,請多多轉(zhuǎn)發(fā),點再看,這是我的動力
one more thing!如果大家想要第一時間看到墨白更新的文章,可以掃描下方的二維碼,關(guān)注我的公眾號。我們下篇文章見!
