溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MySQL中的事務(wù)、4大特性、隔離級別是什么

發(fā)布時(shí)間:2021-10-12 16:12:11 來源:億速云 閱讀:137 作者:iii 欄目:MySQL數(shù)據(jù)庫

本篇內(nèi)容主要講解“MySQL中的事務(wù)、4大特性、隔離級別是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“MySQL中的事務(wù)、4大特性、隔離級別是什么”吧!

MySQL中的事務(wù)、4大特性、隔離級別是什么

本文操作和測試所用的環(huán)境版本是5.7.21

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.21    |
+-----------+
1 row in set (0.00 sec)

記住:我們常見的MySQL存儲(chǔ)引擎中只有InnoDB是支持事務(wù)的。所以下面的操作也都是在InnoDB下做的。

一. 什么是事務(wù)

事務(wù)就是現(xiàn)實(shí)中抽象出來一種邏輯操作,要么都執(zhí)行,要么都不執(zhí)行,不能存在部分執(zhí)行的情況。

比較經(jīng)典的案例就是銀行轉(zhuǎn)賬:小A向小B轉(zhuǎn)賬100元

正常的情況:小A的賬戶扣減100元,小B的賬戶增加100元。

非正常情況: 小A的賬戶扣減100元,小B賬戶金額不變。

非正常情況下,小A賬戶扣減100之后銀行系統(tǒng)出現(xiàn)問題,小B賬戶增加100元的操作并沒有執(zhí)行。也就是兩邊金額對不上了,小A不愿意,小B不愿意,銀行也不愿意啊。事務(wù)的出現(xiàn)就是為了避免非正常情況的出現(xiàn),讓大家都滿意。

二. 事務(wù)的4大特性(ACID)

1. 原子性(Atomicity)

事務(wù)的操作是不可分割的,要么都操作,要么都不操作,就像轉(zhuǎn)賬一樣,不存在中間狀態(tài)。而且這個(gè)原子性不是說只有一個(gè)動(dòng)作,可能會(huì)有很多的操作,但是從結(jié)果上看是不可分割的,也就是說原子性是一個(gè)結(jié)果狀態(tài)。

2. 一致性(Consistency)

執(zhí)行事務(wù)的前后,數(shù)據(jù)保持一致,就像銀行賬戶系統(tǒng)一樣無論事務(wù)是否成功,兩者的賬戶總額應(yīng)該是一樣的。

3. 隔離性(Isolation)

多個(gè)事務(wù)同時(shí)操作數(shù)據(jù)的時(shí)候,多個(gè)事務(wù)直接互相隔離,不會(huì)互相影響。

4. 持久性(Durability)

一個(gè)事務(wù)在提交后對數(shù)據(jù)的影響是永久的,寫入磁盤中不會(huì)丟失。

三. 顯式事務(wù)、隱式事務(wù)

mysql的事務(wù)分為顯式事務(wù)隱式事務(wù),默認(rèn)的事務(wù)是隱式事務(wù),由變量autocommit 在操作的時(shí)候會(huì)自動(dòng)開啟,提交,回滾。

控制的關(guān)鍵命令如下

set autocommit=0; -- 關(guān)閉自動(dòng)提交事務(wù)(顯式)
set autocommit=1; -- 開啟自動(dòng)提交事務(wù)(隱式)
  -- 當(dāng)autocommit=0的時(shí)候手動(dòng)控制事務(wù)
rollback; -- 回滾事務(wù)
commit;  -- 提交事務(wù)
-- 當(dāng)autocommit=1 自動(dòng)提交事務(wù),但是可以控制手動(dòng)提交
start transaction; -- 開啟事務(wù)(或者用begin開啟事務(wù))
commit; -- 提交事務(wù)
rollback; -- 回滾事務(wù)
SAVEPOINT 保存點(diǎn)名稱;  -- 保存點(diǎn)(相當(dāng)于存檔,可以不用回滾全部操作)
rollback to  保存點(diǎn);  -- 回滾到某個(gè)保存點(diǎn) (這個(gè)后面就不測試,知道有這個(gè)操作就行)

先建一張表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. 隱式事務(wù)

-- 看下當(dāng)前autocommit的狀態(tài)是,默認(rèn)是on狀態(tài)
mysql> show variables like 'autocommit'; 
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.01 sec)

--  插入一條數(shù)據(jù)
mysql> insert into ajisun values(1,'阿紀(jì)');
Query OK, 1 row affected (0.00 sec)
mysql> rollback;

-- 執(zhí)行rollback 也是沒有效果的,還是能夠查詢到插入的數(shù)據(jù)(不需要我們手動(dòng)控制commit)
mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿紀(jì)   |
+------+--------+
1 row in set (0.00 sec)

2. 顯式事務(wù)方式1

顯式事務(wù)由我們自己控制事務(wù)的開啟,提交,回滾等操作

-- 開啟顯式事務(wù)-回滾
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿紀(jì)   |
+------+--------+
1 row in set (0.00 sec)

mysql> insert into ajisun values(2,'紀(jì)先生');
Query OK, 1 row affected (0.00 sec)
-- 插入后可以看見2條數(shù)據(jù)
mysql> select * from ajisun;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | 阿紀(jì)      |
|    2 | 紀(jì)先生    |
+------+-----------+
2 rows in set (0.00 sec)
-- 回滾之后上面插入的數(shù)據(jù)就沒了
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿紀(jì)   |
+------+--------+
1 row in set (0.00 sec)
-- 插入一條數(shù)據(jù)
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 數(shù)據(jù)依然存在,說明commit生效,事務(wù)已提交,回滾就不生效了。
mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿紀(jì)   |
|    2 | ajisun |
+------+--------+
2 rows in set (0.00 sec)

3. 顯式事務(wù)方式2

使用start transaction

先改成默認(rèn)的事務(wù) set autocommit=1;

-- 開啟事務(wù)
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)
-- 提交事務(wù)
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)
-- 開啟事務(wù)
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)
-- 回滾事務(wù)
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)

四. 并發(fā)事務(wù)中的問題

如果對表的操作同一時(shí)間只有一個(gè)事務(wù)就不會(huì)有問題,但是這是不可能的?,F(xiàn)實(shí)中都是盡可能的利用,多個(gè)事務(wù)同時(shí)操作。多個(gè)事務(wù)就會(huì)帶來不少的問題,例如臟讀,臟寫,`不可重復(fù)讀,幻讀

1. 臟讀

一個(gè)事務(wù)讀取到另一個(gè)未提交事務(wù)修改后的數(shù)據(jù) 這就是臟讀。

例如兩個(gè)事務(wù)a,b: 同時(shí)操作一條記錄

a事務(wù)修改記錄后還沒有正式提交到數(shù)據(jù)庫,這時(shí)b事務(wù)去讀取,然后用讀取到的數(shù)據(jù)進(jìn)行后續(xù)操作。

如果a事務(wù)回滾了,這個(gè)修改后的數(shù)據(jù)就不存在了,那么b事務(wù)就是在使用一個(gè)不存在的數(shù)據(jù)。這種就是臟數(shù)據(jù)。

2. 臟寫(數(shù)據(jù)丟失)

一個(gè)事務(wù)修改了另一個(gè)未提交事務(wù)修改過的數(shù)據(jù)

例如兩個(gè)事務(wù)a,b: 同時(shí)操作一條記錄

a事務(wù)修改后沒有提交, 接著b事務(wù)也修改同一條數(shù)據(jù),然后b事務(wù)提交數(shù)據(jù)。

如果a事務(wù)回滾自己的修改,同時(shí)也把b事務(wù)的修改也回滾了,造成的問題就是:b事務(wù)修改了 也提交了,但是數(shù)據(jù)庫并沒有改變,這種情況就是臟寫。

3. 不可重復(fù)讀

一個(gè)事務(wù)只能讀到另一個(gè)已經(jīng)提交的事務(wù)修改過的數(shù)據(jù),并且其他事務(wù)每對該數(shù)據(jù)進(jìn)行一次修改并提交后,該事務(wù)都能查詢得到最新值。

也就是在同一個(gè)事務(wù)中多次讀取同一條記錄,得到的內(nèi)容都不一樣(在每次讀取之前都有其他事務(wù)完成修改并提交),這就是不可重復(fù)讀。

4. 幻讀

在一個(gè)事務(wù)內(nèi) 相同條件查詢數(shù)據(jù),先后查詢到的記錄數(shù)不一樣

也就是一個(gè)事務(wù)先根據(jù)某些條件查詢出一些記錄,之后另一個(gè)事務(wù)又向表中插入了符合這些條件的記錄,原先的事務(wù)再次按照該條件查詢時(shí),能把另一個(gè)事務(wù)插入的記錄也讀出來,那就意味著發(fā)生了幻讀

不可重復(fù)讀和幻讀的區(qū)別:不可重復(fù)讀重點(diǎn)在于同一條記錄前后數(shù)據(jù)值不一樣(內(nèi)容的變化),而幻讀重點(diǎn)在于相同查詢條件前后所獲取的記錄數(shù)不一樣(條數(shù)的變化)

五. 事務(wù)的隔離級別

上面說的事務(wù)的并發(fā)問題,在不同的場景下要求不一樣,能接受的問題也不一樣。他們之間的嚴(yán)重性排序如下:

臟寫 > 臟讀 > 不可重復(fù)讀 > 幻讀

MySQL中提供了4種隔離級別來處理這幾個(gè)問題,如下

隔離級別臟讀不可重復(fù)讀幻影讀
READ- UNCOMMITTED
READ-COMMITTED×
REPEATABLE-READ××
SERIALIZABLE×××

SQL 標(biāo)準(zhǔn)定義了四個(gè)隔離級別:

  • READ-UNCOMMITTED(讀未提交): 最低的隔離級別,允許讀取尚未提交的數(shù)據(jù)變更,可能會(huì)導(dǎo)致臟讀、不可重復(fù)讀幻讀。但是并發(fā)度最高

  • READ-COMMITTED(讀已提交): 允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù),可以阻止臟讀,但是幻讀不可重復(fù)讀仍有可能發(fā)生。

  • REPEATABLE-READ(可重復(fù)讀): 對同一字段的多次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改,可以阻止臟讀不可重復(fù)讀,但幻讀仍有可能發(fā)生。

  • SERIALIZABLE(可串行化): 最高的隔離級別,完全服從ACID的隔離級別。所有的事務(wù)依次逐個(gè)執(zhí)行,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,該級別可以防止臟讀、不可重復(fù)讀以及幻讀。并發(fā)度也是最低的

MySQL默認(rèn)采用的 REPEATABLE_READ 隔離級別 
Oracle默認(rèn)采用的 READ_COMMITTED 隔離級別

1. 如何設(shè)置隔離級別

可以通過變量參數(shù)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

設(shè)置全局隔離級別

只對執(zhí)行完該語句之后產(chǎn)生的會(huì)話起作用。

當(dāng)前已經(jīng)存在的會(huì)話無效。

set global transaction_isolation='read-uncommitted';
set global transaction_isolation='read-committed';
set global transaction_isolation='repeatable-read';
set global transaction_isolation='serializable';

例如:

會(huì)話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)
-- 當(dāng)前會(huì)話(設(shè)置之前就已經(jīng)存在的會(huì),級別是默認(rèn)的)
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

會(huì)話B(set之后新建的會(huì)話)

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)

設(shè)置會(huì)話的隔離級別

對當(dāng)前會(huì)話的所有后續(xù)的事務(wù)有效

該語句可以在已經(jīng)開啟的事務(wù)中間執(zhí)行,但不會(huì)影響當(dāng)前正在執(zhí)行的事務(wù)。

如果在事務(wù)之間執(zhí)行,則對后續(xù)的事務(wù)有效。

set session transaction_isolation='read-uncommitted';
set session transaction_isolation='read-committed';
set session transaction_isolation='repeatable-read';
set session transaction_isolation='serializable';

比如:

會(huì)話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)

新建會(huì)話B(依然是默認(rèn)的級別:可重復(fù)讀)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

2. 怎么選擇隔離級別

一般情況下默認(rèn)的可重復(fù)讀就好了,一般很少改這個(gè),除非業(yè)務(wù)場景特殊

記住一點(diǎn):隔離級別越高,并發(fā)問題就越少,但并發(fā)性也就越低,所以還是要根據(jù)業(yè)務(wù)選擇來。

六. 總結(jié)

  • 事務(wù)的四大特性:原子性,一致性,隔離性,持久性

  • 事務(wù)的常見命令:

    set autocommit=0/1; -- 關(guān)閉/開啟自動(dòng)提交事務(wù)
    start transaction; -- 開啟事務(wù)(或者用begin)
    rollback; -- 回滾事務(wù)
    commit; -- 提交事務(wù)
  • 并發(fā)事務(wù)的問題:臟寫 > 臟讀 > 不可重復(fù)讀 > 幻讀

  • 需要熟悉事務(wù)的4種隔離級別以及MySQL默認(rèn)級別

  • 怎么設(shè)置隔離級別(global,session)

到此,相信大家對“MySQL中的事務(wù)、4大特性、隔離級別是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI