SQL92將事務隔離級別分爲了4種,讀未提交,讀已提交,可重複讀,可串行化。不一樣的隔離級別,對於數據的可見性不一樣,就會致使不一樣的正確性。事務的核心在於控制多個客戶端在讀寫共享數據時候的併發問題。這篇文章經過實例研究隔離級別,咱們將從讀未提交開始,一步一步分析。
step1 建立表和基礎數據併發
CREATE TABLE `traning`.`account` ( `id` INT NOT NULL AUTO_INCREMENT COMMENT '主鍵id', `uid` INT NOT NULL COMMENT '用戶uid', `amount` INT NOT NULL COMMENT '金額', PRIMARY KEY (`id`)); INSERT INTO `traning`.`account` (`uid`, `amount`) VALUES ('1', '1000'); INSERT INTO `traning`.`account` (`uid`, `amount`) VALUES ('2', '2000');
step2 修改隔離級別ide
場景1 讀未提交致使髒讀ui
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
關閉會話從新進入MySQL客戶端。
Client2:show variables like 'transaction_isolation';
Client1: start TRANSACTION;
Client2: start TRANSACTION;
Client2: select amount from account where uid=1; (1000)
update account set amount=amount-500 where uid=1;
Client1: select amount from account where uid=1; (讀到別人沒提交事務:500)
-- update account set amount=(amount+100) where uid=1;(數據被鎖,不能更新)
Client2: rollback;(Client1再次讀到的是1000,可是沒有讀)
-- Client1: select amount from account where uid=1; (500)
Client1: update account set amount=(500+100) where uid=1; (讀到舊數據去進行更新操做,致使帳戶丟失500)rest
場景2 讀已提交解決髒讀問題code
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
關閉會話重啓。
Client1:start TRANSACTION;
Client2:start TRANSACTION;
Client2: select amount from account where uid=1; (1000)
update account set amount=amount-500 where uid=1; (500)
Client1:select amount from account where uid=1 (讀取不到別人沒提交的事務:1000);
update account set amount=1000-500 where uid=1;(數據被鎖不能更新)
Client2: rollback;
Client1: update account set amount=(1000+100) where uid=1;
Client1: commit;blog
場景3 讀已提交致使不可重複讀問題事務
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
關閉會話重啓。
Client1:start TRANSACTION;
Client2:start TRANSACTION;
Client1:select amount from account where uid=1; (1000);
Client2:update account set amount=amount-100 where uid=1;
Client2: commit;
Client1: select amount from account where uid=1(amount=900,發現本身錢少了100); it
場景4 可重複讀解決不可重複讀問題io
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Client1:start TRANSACTION;
Client2:start TRANSACTION;
Client2: select amount from account where uid=1;(1000)
Client1:select amount from account where uid=1; (1000);
Client2:commit;
Client1:select amount from account where uid=1;(amount=1000);class
場景5 可重複讀致使幻讀問題
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Client1:start TRANSACTION;
Client2:start TRANSACTION;
Client2: select amount from account ; (2行數據)
Client1:select amount from account ; (2行數據);
Client2:INSERT INTO traning
.account
(uid
, amount
) VALUES ('3', '3000');
Client2:commit;
Client1:select amount from account ;(3條數據);
Clinet1 :update account set amount=1 where id=3(Client讀不到可是能夠更新);
Clinet1 :select amount from account ;(4條數據-phantom read here!!!!影響了client1的判斷和數據);
Clinet1 :commit;
場景6 可序列化解決幻讀問題
Client1:SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Client2:SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Client1:start TRANSACTION;
Client2:start TRANSACTION;
Client2: select amount from account ; (2行數據)
Client1:select amount from account ; (2行數據);
Client2:INSERT INTO traning
.account
(uid
, amount
) VALUES ('3', '3000'); (插入不進去,數據被鎖)
Lock wait timeout exceeded; try restarting transaction
如下是整理的圖:
固然還有第一類丟失更新(髒寫)和第二類丟失更新,第一類丟失更新永遠不會發生,第二類丟失更新會在RU和RC狀況下發生。
這是完整的圖
包含了更多的隔離級別和可能發生數據異常狀況: