
一、事務
事務是數據庫管理系統執行過程中的一個邏輯單位,由一個有限的數據庫操作序列構成。--摘自百科
在MySQL里,事務是在引擎層面實現,比如MyIsam不支持,InnoDB支持
面試清單(Java崗):Java+JVM+數據庫+算法+Spring+中間件+設計模式?shimo.im
二、ACID
提到事務,肯定會想到 ACID 是吧,自行感受一下概念,然后我們來講講隔離性的問題。
- 原子性:事務的所有操作要么全部成功,要么全部回滾。

- 一致性:總是從一個一致性的狀態轉換到另一個一致性的狀態。
- 隔離性:多個事務并發執行時,一個事務的執行不應影響其他事務的執行

- 持久性:已被提交的事務對數據庫的修改應該永久保存在數據庫中。
三、隔離級別
做了多年的 CRUDer,對這幾個詞真是不陌生,要不是出去面試,也真不會去了解。希望大家看完之后,面試的時候,不要慌,跟他剛。
實際上,這些場景都是出現在多個事務同時執行時的場景。
3.1 臟讀(Read Uncommitted)
通俗的講,一個事務在處理過程中讀取了另外一個事務未提交的數據。
你都還沒提交,我就讀到了你剛操作的數據,萬一你回滾了怎么辦,你說這臟不臟。
舉例:

假設打賞的邏輯是:① 我的賬戶+1元;② 你的賬戶-1元。
當你執行到第一個步驟,我去查詢我的賬戶已經是2元了,很開心!!!宣布請大家去擼串!!!但是最后扣款的時候發現你余額不足了,回滾了,我的1元沒了,就很難受!!
3.2 不可重復讀(Non-repeatable Read)
通俗的講,一個事務范圍內,多次查詢某個數據,卻得到不同的結果。
與臟讀的區別:臟讀是讀到未提交的數據,而不可重復讀讀到的卻是已經提交的數據,但實際上是違反了事務的一致性原則。
舉例:

假設我查了下賬戶余額,看到你們給小編打賞了1塊錢,很開心!!!宣布請大家去擼串!!!在付款之前,錢被另外一個人取走,又查詢到沒錢了,被留下來洗碗了!!!
因為我查詢完后,這條數據沒鎖住,又被別的事務更新了,導致當前事務每次都是讀到最新的數據。
3.3 幻讀
在Repeatable Read隔離級別下,一個事務可能會遇到幻讀(Phantom Read)的問題。
事務A讀取與搜索條件相匹配的若干行。事務B以插入或刪除行等方式來修改事務A的結果集,然后再提交。
舉例:

看到了嗎,在一個事務A中,第一次查詢某條記錄,是沒有的,但是,當試圖更新這條不存在的記錄時,竟然能成功,并且,再次讀取同一條記錄,它就神奇地出現了。
實際上,在InnoDB引擎中,對于索引的掃描,不僅鎖住掃描到的索引,而且還鎖住這些索引覆蓋的范圍(gap),因此這個范圍是內插入數據是不允許的。
四、mysql模擬事務隔離性測試
SELECT @@session.tx_isolation;
SELECT @@tx_isolation; SET SESSION TRANSACTION ISOLATION LEVEL read uncommitted;
SET SESSION TRANSACTION ISOLATION LEVEL read committed;
SET SESSION TRANSACTION ISOLATION LEVEL repeatable read;
SET SESSION TRANSACTION ISOLATION LEVEL serializable; start transaction;--建表
drop table AMOUNT;
CREATE TABLE `AMOUNT` (
`id` varchar(10) NULL,
`money` numeric NULL
)
;
--插入數據
insert into amount(id,money) values('A', 800);
insert into amount(id,money) values('B', 200);
insert into amount(id,money) values('C', 1000);
--測試可重復讀,插入數據
insert into amount(id,money) values('D', 1000);--設置事務
SET SESSION TRANSACTION ISOLATION LEVEL read uncommitted;
SELECT @@tx_isolation;
--開啟事務
start transaction;--臟讀演示,讀到其他事務未提交的數據
--案列1,事務一:A向B轉200,事務二:查看B金額變化,事務一回滾事務
update amount set money = money - 200 where id = 'A';
update amount set money = money + 200 where id = 'B';--不可重復讀演示,讀到了其他事務提交的數據
--案列2,事務一:B向A轉200,事務二:B向C轉200轉100
SET SESSION TRANSACTION ISOLATION LEVEL read committed; --開啟事務
start transaction;
--兩個事務都查一下數據(轉賬之前需要,查一下金額是否夠滿足轉賬)
select * from amount;
--事務一:B向A轉200
update amount set money = money - 200 where id = 'B';
update amount set money = money + 200 where id = 'A';commit;
--事務二:B向C轉200轉100
update amount set money = money - 100 where id = 'B';
update amount set money = money + 100 where id = 'C';
commit;
--從事務二的角度來看,讀到了事務一提交事務的數據,導致金額出現負數--幻讀演示
--案列3,事務一:B向A轉200,事務二:B向C轉200轉100
SET SESSION TRANSACTION ISOLATION LEVEL repeatable read; --開啟事務
start transaction;
--兩個事務都查一下數據(轉賬之前需要,查一下金額是否夠滿足轉賬)
select * from amount;
--事務一:B向A轉200
update amount set money = money - 200 where id = 'B';
update amount set money = money + 200 where id = 'A';commit;
--事務二:B向C轉200轉100
update amount set money = money - 100 where id = 'B';
update amount set money = money + 100 where id = 'C';
commit;
--從事務二的角度來看,讀到了事務一提交事務的數據,導致金額出現負數
作者:Java2B
原文鏈接:https://juejin.im/post/5e1417006fb9a047f3363c41