【資料庫】對資料庫事務的思考
阿新 • • 發佈:2019-02-03
紙上得來終覺淺,絕知此事要躬行!
一 思考
- 事務是解決什麼問題的?
- 為了解決這些問題,事務使用了哪些策略或手段?
- 髒讀,幻讀,不可重複讀,概念理解
二 基礎知識
1. 設定事務等級
- read uncommitted:小名等不及,總能看到最新資料,無論改動是否提交
- read commited:小名老實人,目不斜視,只看提交後的更新
- repeatable read:小名一根筋,它檢視過的資料,每次查詢結果不變,不管其它事務是否提交修改
- serializable:小名等等等,別人改了,它就等改動提交後再看;它看了,別人必須等它提交了再改
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;
##2. 資料操作
create database test;
use test;
create table person (
name varchar (30),
age int
);
insert into person values('xiaoerhei', 18);
update person set age=age+1 where name='xiaoerhei';
select * from person;
3. 檢視資料庫狀態
show processlist;
show open tables from test;
三 併發場景梳理
事務級別
- ru : read uncommitted
- rc : read committed
- rr : repeatable read
- sz : serializable
事務組合:
[
(ru, ru), (ru, rc), (ru, rr), (ru, sz),
(rc, ru), (rc, rc), (rc, rr), (rc, sz),
(rr, ru), (rr, rc), (rr, rr), (rr, sz),
(sz, ru), (sz, rc), (sz, rr), (sz, sz)
]
一般情況下,業務介面的事務級別都是一樣的,比如 spring 中進行事務管理時,相同的 service 介面,一般配置為相同的事務級別。
因此,[ (ru, ru), (rc, rc), (rr, rr), (sz, sz)] 這四種事務組合更常見。
事務流程說明:
- 事務名稱: A,B
- $ : start transaction
- U : update/insert/delete
- Q : select
- R :rollback
- # : commit
設計時,事務的內容要儘量小而美,而不是大而全。事務越大,併發時流程的可能性越多,問題越複雜。下面僅列舉一些典型的例子。
示例:
$(A, B) -> U(A) -> Q(B) -> #(A, B)
$(A, B) -> Q(A) -> U(B) -> #(A, B)
$(A, B) -> U(A) -> U(B) -> #(A, B)
$(A, B) -> Q(B) -> U(A) -> Q(B) -> #(A, B)
$(A, B) -> Q(B) -> U(A) -> #(A) -> Q(B) -> #(B)
$(A, B) -> Q(B) -> U(A) -> #(B) -> R(A) -> #(A)
$(A, B) -> U(A) -> U(B) -> R(A) -> #(B)
$(A) -> U(A) ->$(B) -> Q(B) -> #(A, B)
$(A) -> Q(A) ->$(B) -> U(B) -> #(A, B)
備註: $(A, B) -> U(A) -> Q(B) -> #(A, B) 的意思是,事務同時開啟,事務 A 更新某資料 D,然後事務 B 查詢 D 的資訊,然後事務提交。
結果說明:
- SD : sql done, 執行 sql 完成;
- SB : sql block, 執行 sql 阻塞一定時間後完成;
- SE : sql error, 執行 sql 阻塞超時異常;
- DR : dirty read,髒讀
- UR : unrepeatable read,不可重複讀
- PR : phantom read,幻讀
- OD : old data, 老資料
備註
sql 異常是否會引起事務終結並回滾,是可以配置的,SET XACT_ABORT = ON/OFF
四 示例分析
法無常法,因地制宜,要結合實際的應用場景去分析利弊,進而判斷是否滿足需求
scenario | (ru, ru) | (ru, rc) | (ru, rr) | (ru, sz) |
---|---|---|---|---|
$(A, B) -> U(A) -> Q(B) -> #(A, B) | ||||
$(A, B) -> Q(A) -> U(B) -> #(A, B) | ||||
$(A, B) -> U(A) -> U(B) -> #(A, B) | ||||
$(A, B) -> Q(B) -> U(A) -> Q(B) -> #(A, B) | ||||
$(A, B) -> Q(B) -> U(A) -> #(A) -> Q(B) -> #(B) | ||||
$(A, B) -> Q(B) -> U(A) -> #(B) -> R(A) -> #(A) | ||||
$(A, B) -> U(A) -> U(B) -> R(A) -> #(B) | ||||
(B) -> Q(B) -> #(A, B) | ||||
(B) -> U(B) -> #(A, B) |
1 (ru, rc)
-
$(A, B) -> U(A) -> Q(B) -> #(A, B)
- B 讀取資料的實時性會受到影響。
- 儘管 A 已經修改了資料,但是 B 要等到 A commit 之後才能看到更新。
-
$(A, B) -> Q(B) -> U(A) -> #(A) -> Q(B) -> #(B)
- A 更新並提交後,B 再次查詢被更新了的資料
- B 兩次查詢的結果不一致
-
$(A, B) -> U(A) -> U(B) -> #(A, B)
U(A)
insert into person values('sven', 30);
U(B)
update person set age=age+1;
- 這種情況下,sven 的年齡是不會被加 1 的。
- 如果 A,B 對同一資料進行更改時,B 會阻塞。
2 (ru, rr)
-
$(A, B) -> Q(B) -> U(A) -> #(A) -> Q(B) -> #(B)
- 儘管 A 已經提交了更新,B 兩次查詢的結果仍然一致
3 (ru, sz)
-
$(A, B) -> U(A) -> Q(B) -> #(A, B)
- 資料被 A 更新後,B 查詢該資料時會阻塞,直到 A 事務提交
(未完待續 …)