1. 程式人生 > 其它 >MySQL 事務和事務隔離

MySQL 事務和事務隔離

目錄

事務隔離:為什麼你修改了我還看不見?

事務的基礎知識

事務transaction:指一組SQL語句,通常一個事務對應一個完整的業務。
回退rollback:指撤銷指定SQL語句的過程
提交commit:指將未儲存的SQL語句結果寫入資料庫表

事務處理機制可以維持資料庫的完整性 ,保證成批的MySQL操作要麼完全執行,要麼完全不執行

事務支援在引擎層實現,但並不是所有的引擎都支援事務,InnoDB支援事務

事務四大特性(ACID)

原子性(Atomicity):事務是最小單位,不可再分
一致性(Consistency):事務要求所有的DML(資料操作增刪改)語句操作的時候,必須保證同時成功或者同時失敗
隔離性(Isolation):同一時間,只允許一個事務請求同一資料,不同的事務之間彼此沒有任何干擾。比如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉賬。
永續性(Durability):事務完成後,事務對資料庫的所有更新將被儲存到資料庫,不能回滾。

控制事務處理

事務的啟動方式:BEGIN或START TRANSACTION :標識事務的開始,COMMIT和ROLLBACK語句執行後,事務會自動關閉。

修改預設行為

SET autocommit = FALSE(/0)關閉預設提交行為。

autocommit針對每個連線,而不是伺服器

一般的Mysql語句都是直接針對資料庫表執行和編寫的,隱含提交。(DML可以修改預設提交行為)
在事務處理塊中,提交需要指明。

區別 DDL DML
具體操作 create、表的管理 增刪(delete)改
是否可以回滾 操作一旦執行,不可回滾,執行完DDL之後一定會執行一次COMMIT,且不受autocommit影響 預設情況下,一旦執行,不可回滾
如果在執行DML之前,修改預設提交行為SET autocommit = FALSE,則執行的DML操作就可以回滾

建議使用set autocommit=1

commit work and chain

對於一個需要頻繁使用事務的業務,在 autocommit 為 1 的情況下,用 begin 顯式啟動的事務,如果執行 commit 則提交事務,再使用begin重新開啟下一個事務。
如果執行 commit work and chain,則是提交事務並自動啟動下一個事務,這樣也省去了再次執行 begin 語句的開銷。同時帶來的好處是從程式開發的角度明確地知道每個語句是否處於事務中。

COMMIT與ROLLBACK

COMMIT:不出錯時提交資料。一旦執行COMMIT,則資料被永久的儲存在資料庫中,該資料不可以回滾

ROLLBACK:回滾資料。一旦執行ROLLBACK,則可以實現資料的回滾(不一定成功),回滾到最近的一次COMMIT之後

使用保留點

設定保留點的目的是實現部分提交與回滾

建立保留點:SAVEPOINT 保留點

案例

START TRANSACTION;
DELETE FROM USER WHERE id = 1;
SAVEPOINT a;
DELETE FROM USER WHERE id = 2;
ROLLBACK TO a;

說明

保留點在事務處理完成後自動釋放。也可以用RELEASE TRANSACTION 保留點明確釋放保留點。沒有指定保留點,會報異常。

隔離性與隔離級別

資料庫有多個事物同時執行時,可能出現

  • 髒讀 dirty read 某個事務已更新一份資料,另一個事務在此時讀取了同一份資料,由於某些原因,前一個RollBack了操作,則後一個事務所讀取的資料就會是不正確的
  • 不可重複讀 non-repeatable read 在一個事務的兩次查詢之中資料不一致。
  • 幻讀phantom read 系統管理員A將資料庫中所有學生的成績從具體分數改為ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。

不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。解決不可重複讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表

為了解決這些問題,提出了"隔離級別"

SQL 標準的事務隔離級別包括:

隔離級別 描述 避免髒讀 避免不可重複讀 避免幻讀
讀未提交(read uncommitted) 一個事務還沒提交時,它做的變更就能被別的事務看到。 × × ×
讀提交(read committed) 一個事務提交之後,它做的變更才會被其他事務看到。 × ×
可重複讀(repeatable read) 事務在執行期間看到的資料前後必須是一致的。A事務無論執行多少次,只要不提交,B事務查詢值都不變,B事務僅查詢B事務開始時那一瞬間的資料快照。(MySQL8預設隔離級別) ×
序列化(serializable ) 對於同一行記錄,“寫”會加“寫鎖”,“讀”會加“讀鎖”。當出現讀寫鎖衝突(讀讀不衝突)的時候,後訪問的事務必須等前一個事務執行完成,才能繼續執行。

隔離級別案例理解

create table T(c int) engine=InnoDB;
insert into T(c) values(1);

假設資料表 T 中只有一列,其中一行的值為 1,下面是按照時間順序執行兩個事務的行為。

事物A 事物B 讀未提交 讀提交 可重複讀 序列化
啟動事物,查詢得到值1 啟動事物 此行被事物A加鎖

查詢得到值1

將1修改到2 這裡被事物A加鎖了,只有等事物A執行完畢,才可以執行
查詢得到值V1 2 1 1 1

提交事務B
查詢得到值V2 2 2 1
事務在執行期間看到的資料前後必須是一致的
1
提交事物A
查詢得到值V3 2 2 2 2

在實現上,資料庫裡面會建立一個檢視,訪問的時候以檢視的邏輯結果為準。

隔離級別 檢視實現
讀未提交 直接返回記錄上的最新值,沒有檢視概念
讀提交 檢視是在每個SQL語句開始執行的時候建立的
可重複讀 檢視在事務啟動時建立的,可以看作檢視是靜態的,整個事務存在期間都用這個檢視。
這樣才可以保證執行期間讀到的資料一致。
序列化 直接用加鎖的方式來避免並行訪問。

隔離級別的設定

Oracle 資料庫的預設隔離級別是“讀提交”,因此對於一些從 Oracle 遷移到 MySQL 的應用,為保證資料庫隔離級別的一致,一定要將 MySQL 的隔離級別設定為“讀提交”。

transaction-isolation引數

語法:set 作用域 transaction isolation level 事務隔離級別

說明
1.若沒有輸入作用域直接修改transaction isolation,顯示修改成功,但實際上沒有修改!
2.設定本次會話session的事務隔離級別,只在本會話有效,不會影響到其它會話
3.設定全域性global的事務隔離級別,該設定不會影響當前已經連線的會話,設定完畢後,新開啟的會話,將使用新設定的事務隔離級別

# 檢視mysql的隔離級別:可重複讀REPEATABLE-READ
mysql> show variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)
# 使用Mysql查詢
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)


# 設定本次會話為讀提交READ-COMMITTED,僅在本次會話有效,不影響其他會話,
mysql> set session transaction isolation level read committed;
mysql>  select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-COMMITTED          |
+-------------------------+
1 row in set (0.00 sec)

# 設定全域性的事務隔離級別,該設定不會影響當前已經連線的會話,設定完畢後,新開啟的會話,將使用新設定的事務隔離級別
mysql> set global transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)
mysql>  select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-COMMITTED          |
+-------------------------+
1 row in set (0.00 sec)

事務隔離的實現

用MVCC機制實現事務隔離

後續學習到了補充