共計 7865 個字符,預計需要花費 20 分鐘才能閱讀完成。
本篇內容主要講解“MySQL 中的事務、4 大特性、隔離級別是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓丸趣 TV 小編來帶大家學習“MySQL 中的事務、4 大特性、隔離級別是什么”吧!
本文操作和測試所用的環境版本是 5.7.21
mysql select version();
+-----------+
| version() |
+-----------+
| 5.7.21 |
+-----------+
1 row in set (0.00 sec)
記住:我們常見的 MySQL 存儲引擎中只有 InnoDB 是支持事務的。所以下面的操作也都是在 InnoDB 下做的。
一. 什么是事務
事務就是現實中抽象出來一種邏輯操作,要么都執行,要么都不執行,不能存在部分執行的情況。
比較經典的案例就是銀行轉賬:小 A 向小 B 轉賬 100 元
正常的情況:小 A 的賬戶扣減 100 元,小 B 的賬戶增加 100 元。
非正常情況: 小 A 的賬戶扣減 100 元,小 B 賬戶金額不變。
非正常情況下,小 A 賬戶扣減 100 之后銀行系統出現問題,小 B 賬戶增加 100 元的操作并沒有執行。也就是兩邊金額對不上了,小 A 不愿意,小 B 不愿意,銀行也不愿意啊。事務的出現就是為了避免非正常情況的出現,讓大家都滿意。
二. 事務的 4 大特性(ACID)
1. 原子性(Atomicity)
事務的操作是不可分割的,要么都操作,要么都不操作,就像轉賬一樣,不存在中間狀態。而且這個原子性不是說只有一個動作,可能會有很多的操作,但是從結果上看是不可分割的,也就是說原子性是一個結果狀態。
2. 一致性(Consistency)
執行事務的前后,數據保持一致,就像銀行賬戶系統一樣無論事務是否成功,兩者的賬戶總額應該是一樣的。
3. 隔離性(Isolation)
多個事務同時操作數據的時候,多個事務直接互相隔離,不會互相影響。
4. 持久性(Durability)
一個事務在提交后對數據的影響是永久的,寫入磁盤中不會丟失。
三. 顯式事務、隱式事務
mysql 的事務分為顯式事務和隱式事務, 默認的事務是隱式事務,由變量 autocommit 在操作的時候會自動開啟,提交,回滾。
控制的關鍵命令如下
set autocommit=0; -- 關閉自動提交事務(顯式)set autocommit=1; -- 開啟自動提交事務(隱式) -- 當 autocommit= 0 的時候手動控制事務
rollback; -- 回滾事務
commit; -- 提交事務
-- 當 autocommit=1 自動提交事務,但是可以控制手動提交
start transaction; -- 開啟事務(或者用 begin 開啟事務)commit; -- 提交事務
rollback; -- 回滾事務
SAVEPOINT 保存點名稱; -- 保存點 (相當于存檔,可以不用回滾全部操作)
rollback to 保存點; -- 回滾到某個保存點 (這個后面就不測試,知道有這個操作就行)
先建一張表 ajisun
mysql create table ajisun(id int(5), name varchar(20) character set utf8 COLLATE utf8_bin ) engine=innodb character set= utf8mb4 COLLATE = utf8mb4_bin;
Query OK, 0 rows affected (0.03 sec)
1. 隱式事務
-- 看下當前 autocommit 的狀態是,默認是 on 狀態
mysql show variables like autocommit
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.01 sec)
-- 插入一條數據
mysql insert into ajisun values(1, 阿紀
Query OK, 1 row affected (0.00 sec)
mysql rollback;
-- 執行 rollback 也是沒有效果的,還是能夠查詢到插入的數據(不需要我們手動控制 commit)mysql select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 1 | 阿紀 |
+------+--------+
1 row in set (0.00 sec)
2. 顯式事務方式 1
顯式事務由我們自己控制事務的開啟,提交,回滾等操作
-- 開啟顯式事務 - 回滾
mysql set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 1 | 阿紀 |
+------+--------+
1 row in set (0.00 sec)
mysql insert into ajisun values(2, 紀先生
Query OK, 1 row affected (0.00 sec)
-- 插入后可以看見 2 條數據
mysql select * from ajisun;
+------+-----------+
| id | name |
+------+-----------+
| 1 | 阿紀 |
| 2 | 紀先生 |
+------+-----------+
2 rows in set (0.00 sec)
-- 回滾之后上面插入的數據就沒了
mysql rollback;
Query OK, 0 rows affected (0.00 sec)
mysql select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 1 | 阿紀 |
+------+--------+
1 row in set (0.00 sec)
-- 插入一條數據
mysql insert into ajisun values(2, ajisun
Query OK, 1 row affected (0.01 sec)
-- 提交
mysql commit;
Query OK, 0 rows affected (0.00 sec)
-- 回滾
mysql rollback;
Query OK, 0 rows affected (0.00 sec)
-- 先提交 commit,在 rollback 數據依然存在,說明 commit 生效,事務已提交,回滾就不生效了。mysql select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 1 | 阿紀 |
| 2 | ajisun |
+------+--------+
2 rows in set (0.00 sec)
3. 顯式事務方式 2
使用 start transaction
先改成默認的事務 set autocommit=1;
-- 開啟事務
mysql start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql delete from ajisun where id=1;
Query OK, 1 row affected (0.00 sec)
-- 提交事務
mysql commit;
Query OK, 0 rows affected (0.01 sec)
mysql select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 2 | ajisun |
+------+--------+
1 row in set (0.00 sec)
-- 開啟事務
mysql start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql delete from ajisun where id =2;
Query OK, 1 row affected (0.01 sec)
-- 回滾事務
mysql rollback;
Query OK, 0 rows affected (0.01 sec)
-- 刪除操作失效了
mysql select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 2 | ajisun |
+------+--------+
1 row in set (0.00 sec)
四. 并發事務中的問題
如果對表的操作同一時間只有一個事務就不會有問題,但是這是不可能的。現實中都是盡可能的利用,多個事務同時操作。多個事務就會帶來不少的問題,例如臟讀,臟寫,` 不可重復讀,幻讀
1. 臟讀
一個事務讀取到另一個未提交事務修改后的數據 這就是臟讀。
例如兩個事務 a,b: 同時操作一條記錄
a 事務修改記錄后還沒有正式提交到數據庫,這時 b 事務去讀取,然后用讀取到的數據進行后續操作。
如果 a 事務回滾了,這個修改后的數據就不存在了,那么 b 事務就是在使用一個不存在的數據。這種就是臟數據。
2. 臟寫(數據丟失)
一個事務修改了另一個未提交事務修改過的數據
例如兩個事務 a,b: 同時操作一條記錄
a 事務修改后沒有提交, 接著 b 事務也修改同一條數據,然后 b 事務提交數據。
如果 a 事務回滾自己的修改,同時也把 b 事務的修改也回滾了,造成的問題就是:b 事務修改了 也提交了,但是數據庫并沒有改變,這種情況就是臟寫。
3. 不可重復讀
一個事務只能讀到另一個已經提交的事務修改過的數據,并且其他事務每對該數據進行一次修改并提交后,該事務都能查詢得到最新值。
也就是在同一個事務中多次讀取同一條記錄,得到的內容都不一樣(在每次讀取之前都有其他事務完成修改并提交),這就是不可重復讀。
4. 幻讀
在一個事務內 相同條件查詢數據,先后查詢到的記錄數不一樣
也就是一個事務先根據某些條件查詢出一些記錄,之后另一個事務又向表中插入了符合這些條件的記錄,原先的事務再次按照該條件查詢時,能把另一個事務插入的記錄也讀出來,那就意味著發生了幻讀
不可重復讀和幻讀的區別:不可重復讀重點在于同一條記錄前后數據值不一樣(內容的變化),而幻讀重點在于相同查詢條件前后所獲取的記錄數不一樣(條數的變化)
五. 事務的隔離級別
上面說的事務的并發問題,在不同的場景下要求不一樣,能接受的問題也不一樣。他們之間的嚴重性排序如下:
臟寫 臟讀 不可重復讀 幻讀
MySQL 中提供了 4 種隔離級別來處理這幾個問題,如下
隔離級別臟讀不可重復讀幻影讀 READ- UNCOMMITTED√√√READ-COMMITTED×√√REPEATABLE-READ××√SERIALIZABLE×××
SQL 標準定義了四個隔離級別:
READ-UNCOMMITTED(讀未提交):最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致臟讀、不可重復讀和幻讀。但是并發度最高
READ-COMMITTED(讀已提交):允許讀取并發事務已經提交的數據,可以阻止臟讀,但是幻讀和不可重復讀仍有可能發生。
REPEATABLE-READ(可重復讀):對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生。
SERIALIZABLE(可串行化):最高的隔離級別,完全服從 ACID 的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,該級別可以防止臟讀、不可重復讀以及幻讀。并發度也是最低的
MySQL 默認采用的 REPEATABLE_READ 隔離級別
Oracle 默認采用的 READ_COMMITTED 隔離級別
1. 如何設置隔離級別
可以通過變量參數 transaction_isolation 查看隔離級別
mysql SELECT @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
mysql show variables like %transaction_isolation%
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)
修改的命令:SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL $[level];
level 的值就是 4 中隔離級別 READ-UNCOMMITTED READ-COMMITTED REPEATABLE-READ SERIALIZABLE
設置全局隔離級別
只對執行完該語句之后產生的會話起作用。
當前已經存在的會話無效。
set global transaction_isolation= read-uncommitted
set global transaction_isolation= read-committed
set global transaction_isolation= repeatable-read
set global transaction_isolation= serializable
例如:
會話 A
mysql set global transaction_isolation= serializable
Query OK, 0 rows affected (0.01 sec)
mysql select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE |
+--------------------------------+
1 row in set (0.00 sec)
-- 當前會話(設置之前就已經存在的會,級別是默認的)mysql select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
會話 B(set 之后新建的會話)
mysql select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE |
+--------------------------------+
1 row in set (0.00 sec)
mysql select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| SERIALIZABLE |
+-------------------------+
1 row in set (0.00 sec)
設置會話的隔離級別
對當前會話的所有后續的事務有效
該語句可以在已經開啟的事務中間執行,但不會影響當前正在執行的事務。
如果在事務之間執行,則對后續的事務有效。
set session transaction_isolation= read-uncommitted
set session transaction_isolation= read-committed
set session transaction_isolation= repeatable-read
set session transaction_isolation= serializable
比如:
會話 A
mysql set session transaction_isolation= read-uncommitted
Query OK, 0 rows affected (0.00 sec)
mysql select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED |
+-------------------------+
1 row in set (0.00 sec)
新建會話 B(依然是默認的級別:可重復讀)
mysql select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
2. 怎么選擇隔離級別
一般情況下默認的可重復讀就好了,一般很少改這個,除非業務場景特殊
記住一點:隔離級別越高,并發問題就越少,但并發性也就越低,所以還是要根據業務選擇來。
六. 總結
事務的四大特性:原子性,一致性,隔離性,持久性
事務的常見命令:
set autocommit=0/1; -- 關閉 / 開啟自動提交事務
start transaction; -- 開啟事務(或者用 begin)rollback; -- 回滾事務
commit; -- 提交事務
并發事務的問題:臟寫 臟讀 不可重復讀 幻讀
需要熟悉事務的 4 種隔離級別以及 MySQL 默認級別
怎么設置隔離級別(global,session)
到此,相信大家對“MySQL 中的事務、4 大特性、隔離級別是什么”有了更深的了解,不妨來實際操作一番吧!這里是丸趣 TV 網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!