數(shù)據(jù)庫(kù)事務(wù)
1.1數(shù)據(jù)庫(kù)版本
Mysql8.0.12
1.2事務(wù)是由一組SQL語(yǔ)句組成的邏輯處理單元,事務(wù)具有以下4個(gè)屬性,通常簡(jiǎn)稱為 事務(wù)的ACID屬性
原子性(Atomicity) :事務(wù)是一個(gè)原子操作單元,其對(duì)數(shù)據(jù)的修改,要么全都執(zhí) 行,要么全都不執(zhí)行。
一致性(Consistent) :在事務(wù)開始和完成時(shí),數(shù)據(jù)都必須保持一致狀態(tài)。這意 味著所有相關(guān)的數(shù)據(jù)規(guī)則都必須應(yīng)用于事務(wù)的修改,以保持?jǐn)?shù)據(jù)的完整性;事務(wù)結(jié)束時(shí),所有的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(如B樹索引或雙向鏈表)也都必須是正確的。
隔離性(Isolation) :數(shù)據(jù)庫(kù)系統(tǒng)提供一定的隔離機(jī)制,保證事務(wù)在不受外部并 發(fā)操作影響的“獨(dú)立”環(huán)境執(zhí)行。這意味著事務(wù)處理過程中的中間狀態(tài)對(duì)外部是 不可見的,反之亦然。
持久性(Durable) :事務(wù)完成之后,它對(duì)于數(shù)據(jù)的修改是永久性的,即使出現(xiàn)系 統(tǒng)故障也能夠保持。
1.3并發(fā)事務(wù)處理帶來的問題
更新丟失(Lost Update)
當(dāng)兩個(gè)或多個(gè)事務(wù)選擇同一行,然后基于最初選定的值更新該行時(shí),由于每 個(gè)事務(wù)都不知道其他事務(wù)的存在,就會(huì)發(fā)生丟失更新問題–最后的更新覆蓋了由其 他事務(wù)所做的更新。
臟讀(Dirty Reads)
一個(gè)事務(wù)正在對(duì)一條記錄做修改,在這個(gè)事務(wù)完成并提交前,這條記錄的數(shù) 據(jù)就處于不一致的狀態(tài);這時(shí),另一個(gè)事務(wù)也來讀取同一條記錄,如果不加控制,第二個(gè)事務(wù)讀取了這些“臟”數(shù)據(jù),并據(jù)此作進(jìn)一步的處理,就會(huì)產(chǎn)生未提 交的數(shù)據(jù)依賴關(guān)系。這種現(xiàn)象被形象的叫做“臟讀”。 一句話:事務(wù)A讀取到了事務(wù)B已經(jīng)修改但尚未提交的數(shù)據(jù),還在這個(gè)數(shù)據(jù)基 礎(chǔ)上做了操作。此時(shí),如果B事務(wù)回滾,A讀取的數(shù)據(jù)無效,不符合一致性要求。
不可重讀(Non-Repeatable Reads)
一個(gè)事務(wù)在讀取某些數(shù)據(jù)后的某個(gè)時(shí)間,再次讀取以前讀過的數(shù)據(jù),卻發(fā)現(xiàn) 其讀出的數(shù)據(jù)已經(jīng)發(fā)生了改變或某些記錄已經(jīng)被刪除了!這種現(xiàn)象就叫做“不可重復(fù)讀”。 一句話:事務(wù)A讀取到了事務(wù)B已經(jīng)提交的修改數(shù)據(jù),不符合隔離性
幻讀(Phantom Reads)
一個(gè)事務(wù)按相同的查詢條件重新讀取以前檢索過的數(shù)據(jù),卻發(fā)現(xiàn)其他事務(wù)插 入了滿足其查詢條件的新數(shù)據(jù),這種現(xiàn)象就稱為“幻讀”。 一句話:事務(wù)A讀取到了事務(wù)B提交的新增數(shù)據(jù),不符合隔離性
1.4事務(wù)隔離級(jí)別
臟讀”、“不可重復(fù)讀”和“幻讀”,其實(shí)都是數(shù)據(jù)庫(kù)讀一致性問題,必須由數(shù) 據(jù)庫(kù)提供一定的事務(wù)隔離機(jī)制來解決。
?
隔離級(jí)別 | 臟度 | 不可重復(fù)度 | 幻讀 |
---|---|---|---|
讀未提交 | 可能 | 可能 | 可能 |
讀已提交 | 不可能 | 可能 | 可能 |
可重復(fù)讀 | 不可能 | 不可能 | 可能 |
可串型化 | 不可能 | 不可能 | 不可能 |
數(shù)據(jù)庫(kù)的事務(wù)隔離越嚴(yán)格,并發(fā)副作用越小,但付出的代價(jià)也就越大,因?yàn)槭聞?wù)隔 離實(shí)質(zhì)上就是使事務(wù)在一定程度上“串行化”進(jìn)行,這顯然與“并發(fā)”是矛盾的。
同時(shí),不同的應(yīng)用對(duì)讀一致性和事務(wù)隔離程度的要求也是不同的,比如許多應(yīng)用 對(duì)“不可重復(fù)讀"和“幻讀”并不敏感,可能更關(guān)心數(shù)據(jù)并發(fā)訪問的能力。
??串?dāng)前數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別:show variables like 'transaction_isolation';
設(shè)置事務(wù)隔離級(jí)別:set transaction_isolation='REPEATABLE-READ';
2.案例分析
create table if not exists test1.my_name
(
id bigint auto_increment comment '主鍵id'
primary key,
name varchar(20) null comment '名稱',
balance int null comment '余額'
);
INSERT INTO`test1`.`my_name`(`name`,`balance`)VALUES('lilei','450');
INSERT INTO`test1`.`my_name`(`name`,`balance`)VALUES('hanmei', '16000');
INSERT INTO`test1`.`my_name`(`name`,`balance`)VALUES('lucy','2400');
2.1讀未提交
(1)打開一個(gè)客戶端A,并設(shè)置當(dāng)前事務(wù)模式為read uncommitted(未提交 讀),查詢表my_name的初始值
set transaction_isolation='read-uncommitted';
(2)在客戶端A的事務(wù)提交之前,打開另一個(gè)客戶端B,更新表my_name,雖然客戶端B的事務(wù)還沒提交,但是客戶端A就可以查詢到B已經(jīng)更 新的數(shù)據(jù):
(3)一旦客戶端B的事務(wù)因?yàn)槟撤N原因回滾,所有的操作都將會(huì)被撤銷,那 客戶端A查詢到的數(shù)據(jù)其實(shí)就是臟數(shù)據(jù):
(4)在客戶端A執(zhí)行更新語(yǔ)句update account set balance = balance - 50 where id =1,lilei的balance沒有變成350,居然是400,是不是很奇怪,數(shù)據(jù)不 一致啊,如果你這么想就太天真 了,在應(yīng)用程序中,我們會(huì)用400-50=350,并 不知道其他會(huì)話回滾了,要想解決這個(gè)問題可以采用讀已提交的隔離級(jí)別
2.2 讀已提交
(1)打開一個(gè)客戶端A,并設(shè)置當(dāng)前事務(wù)模式為read committed(未提交 讀),查詢表my_name的所有記錄:
set transaction_isolation='read-committed';
(2)在客戶端A的事務(wù)提交之前,打開另一個(gè)客戶端B,更新表my_name
(3)這時(shí),客戶端B的事務(wù)還沒提交,客戶端A不能查詢到B已經(jīng)更新的數(shù) 據(jù),解決了臟讀問題:
(4)客戶端B的事務(wù)提交
(5)客戶端A執(zhí)行與上一步相同的查詢,結(jié)果 與上一步不一致,即產(chǎn)生了不 可重復(fù)讀的問題