一起來學MySQL—事務的隔離級別

事務的含義

事務:一條或多條 sql 語句組成的一個執行單元,這組 sql 語句是一個整體,要麼都順利執行,要麼都不執行,只要在執行的過程中,有一條 sql 語句執行錯誤就全部回滾或部分回滾。

事務的特性

事務總共有 4 大特性:ACID。
A(Atomicity)原子性:一個事務是不可再分割的整體,要麼都執行要麼都不執行

C(Consistency)一致性:一個事務可以使數據從一個一致狀態切換到另外一個一致的狀態。比如 A 和 B 的賬戶上都各有 1000 元,在 A 給 B 轉了 500 元之後,A 的賬戶上 是 500 元,B 的賬戶上是 1500 元,兩人的總額還是 2000 元。

I(Isolation)隔離性:一個事務不受其他事務的干擾,多個事務互相隔離

D(Durability)持久性:一個事務一旦提交了,則它對數據庫中數據的改變就是永久性的

事務的使用步驟

首先事務分爲兩類:一種是隱式事務,一種是顯式事務。
像單條的 insert、update、delete 語句,本身都是一條事務,只不過由 MySQL 自動提交了。
而顯式事務則需要我們自己手動的提交或回滾。

使用顯式事務的步驟:
① 首先要開啓事務,將自動提交關閉。

set autocommit = 0;
start transaction;  #可以省略

② 編寫一組 sql 語句,在其間可以設置會滾點。

savepoint 回滾點名;    #設置回滾點`

③ 結束事務
  提交:commit;
  回滾:rollback;
  回滾到指定的地方:rollback to 回滾點名;

演示 savepoint 的使用:

SET autocommit = 0;
START TRANSACTION;
DELETE FROM account WHERE id=25;
SAVEPOINT a;#設置保存點
DELETE FROM account WHERE id=28;
ROLLBACK TO a;#回滾到保存點

事務的併發問題

當多個事務同時操作同一個數據庫的相同數據時,就會出現事務的併發問題。
那事務的併發問題都有哪些呢?

  • 髒讀: 對於兩個事務 T1, T2。T1 讀取了已經被 T2 更新但還沒有被提交的字段。之後,若 T2 回滾,則 T1 讀取的內容就是臨時且無效的。
  • 不可重複讀:對於兩個事務T1, T2。T1 讀取了一個字段,然後 T2 更新了該字段。之後,T1再次讀取同一個字段,值就不同了。
  • 幻讀:對於兩個事務T1, T2。T1 從一個表中讀取了一個字段, 然後 T2 在該表中插
    入了一些新的行。之後, 如果 T1 再次讀取同一個表, 就會多出幾行

事務的隔離級別

對於事務的併發問題,我們可以通過設置不同的隔離級別來解決這些併發問題。
MySQL 支持 4 種隔離級別:

隔離級別 描述
READ UNCOMMITTED(讀未提交數據) 允許事務讀取未被其他事務提交的變更髒讀,不可重複讀和幻讀的問題都會出現
READ COMMITTED(讀已提交數據) 只允許事務讀取已經被其它事務提交的變更。可以避免髒讀,但不可重複讀和幻讀問題仍然可能出現
REPEATABLE READ(可重複讀) 確保事務可以多次從一個字段中讀取相同的值。可以避免髒讀和不可重複讀,但幻讀的問題仍然存在。
SERIALIZABLE(串行化) 確保事務可以從一個表中讀取相同的行,在這個事務持續期間,禁止其他事務對該表執行插入,更新和刪除操作,所有併發問題都可以避免,但性能十分低下

隔離級別越高, 數據一致性就越好, 但併發性越弱。

補充:
 Oracle 支持 2 種事務隔離級別:READ COMMITED 和 SERIALIZABLE。Oracle 默認的事務隔離級別爲: READCOMMITED。
 Mysql 默認的事務隔離級別爲: REPEATABLE READ。

事務併發問題的演示

每啓動一個 mysql 程序, 就會獲得一個單獨的數據庫連接。每個數據庫連接都有一個全局變量 @@tx_isolation, 表示當前的事務隔離級別。

查看當前的隔離級別: SELECT @@tx_isolation;
設置當前 MySQL 連接的隔離級別:set session transaction isolation level read committed;
設置數據庫系統的全局的隔離級別:set global transaction isolation level read committed;

1、先創建一個表 account,往裏面插入 2 條數據

CREATE TABLE `account` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `username` varchar(20) ,
  `balance` int ,
);

INSERT INTO account(username,balance) VALUES('劉備',1000),('關羽',1000);

2、開啓兩個 MySQL 連接,首先設置數據庫的隔離級別爲:read uncommitted;,演示出現的問題。
在這裏插入圖片描述
3、修改數據庫的隔離級別爲:read committed,解決了髒讀的問題,但是會出現不可重複讀的問題。
在這裏插入圖片描述
4、修改數據庫的隔離級別爲:repeatable read,解決了髒讀和不可重複讀的問題,但是會出現幻讀。
在這裏插入圖片描述
5、修改數據庫的隔離級別爲:serializable,髒讀、不可重複讀、幻讀的問題都解決了。
在這裏插入圖片描述
最後,總結一下,不同的隔離級別都能解決什麼問題:

髒讀 不可重複讀 幻讀
READ UNCOMMITTED × × ×
READ COMMITTED × ×
REPEATABLE READ ×
SERIALIZABLE
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章