1.事務的四大特性(ACID)
原子性(atomicity):一個事務是不可分割的工作單位,事務中的操作要麼一起發生,要麼一起不發生
一致性(consistency):事務前後的數據必須保持一致
隔離性(isolation):多個事務之間數據要相互隔離
持久性(durability):事務一旦被提交,改變是永久性的
2.隔離性問題
2.1隔離性分析
- 隔離性問題本質上就是多線程的併發安全問題
- 如果兩個線程併發修改,必然會產生多線程安全問題,必須隔離
- 如果兩個線程併發查詢,必然沒有問題,不需要隔離
- 如果一個線程修改,一個線程查詢,在不同的應用場景下可能有問題,也可能沒問題
2.2隔離性可能造成的問題
髒讀(dirty reads):一個事務讀取到另一個事務未提交的數據
實現髒讀過程:
1.打開兩個窗口,因爲SESSION表示的是當前窗口有效,所以窗口1和窗口2都要先執行下面語句,將隔離級別設置爲最低
set session transaction isolation level read uncommitted;
2. 執行窗口1中圈住的語句
3.執行完窗口1中的語句後回到窗口2中開啓事務並執行查詢,此時窗口2中的數據查詢a用戶已經被扣款100,b用戶賬戶已經被增加100(因爲窗口1還未完成提交,但是允許查詢,故出現了髒讀)
4.執行窗口1的回滾操作
5.回到窗口2中繼續查詢數據,此時展示的值就是窗口一回滾後的值
2.不可重複度(non-repeatable reads) :一個事務多次讀取同一條數據,多次查詢結果不同
測試方法類似於髒讀(此處不再贅述)
窗口1:
start transaction;
select * from user where name='a';
窗口2:
start transaction;
update user set money=money-100 where name='a';
commit;
窗口1:
/#兩次查詢結果不同
select * from user where name='a';
commit;
3.虛讀/幻讀(phantom reads ):出現概率很低,一個事務多次查詢整表數據,查詢到的結果不同
測試方法類似於髒讀(此處不再贅述)
窗口1:
start transaction;
select sum(money) from user;
窗口2:
start transaction;
insert into user values(3,'c',5000);
commit;
窗口1:
#兩次查詢結果不同
select sum(money) from user;
commit;
3.隔離級別
數據庫針對不同場景需求設計了不同的隔離級別
- read uncommitted:不做任何隔離,可能造成髒讀、不可重複讀、虛讀(幻讀)問題
- read committed:可以防止髒讀,但是不能防止不可重複讀、虛讀(幻讀)問題
- repeatable read:可以防止髒讀、不可重複讀,但是不能防止虛讀(幻讀)問題
- serializable:可以防止所有隔離性問題,但是數據庫被設計爲串行化的數據庫,性能很低
安全性:serializable>repeatable read>read committed>read uncommitted
效率:read uncommitted>read committed>repeatable read>serializable
MySQL默認隔離級別:repeatable read
Oracle默認隔離級別:read committed
操作隔離級別
查詢數據庫的隔離級別
select @@tx_isolation;
修改隔離級別
set [session/global] transaction isolation level xxx;
不寫默認爲session,表示只修改當前客戶端的隔離級別,不影響其他客戶端
如果設置爲global,表示修改數據庫默認的隔離級別,但是當前窗口無效
例如:set session transaction isolation level serializable;