單機(jī)事務(wù)

分布式相關(guān)的內(nèi)容非常多, 本次分享主要是從分布式事務(wù)切入的, 所以主要講的是分布式的環(huán)境下, 怎么做事務(wù); 要講分布式事務(wù), 我覺得還是有必要提一下單機(jī)事務(wù)的, 單機(jī)事務(wù)的很多特性其實(shí)在分布式事務(wù)中也需要考慮到; 那么今天在這里, 我們主要從兩方面來解讀下單機(jī)事務(wù):

  1. 是什么? : 事務(wù)是什么?
  2. 怎么做?: 事務(wù)是怎么實(shí)現(xiàn)的?

1. 事務(wù)是什么?

我們的系統(tǒng)大體能分為兩類:

a. 數(shù)據(jù)密集型;

b. 計(jì)算密集型;

我們?nèi)粘9ぷ髦懈嘟佑|到的是數(shù)據(jù)密集型, 也就無可避免的接觸到數(shù)據(jù)持久話的問題了, 現(xiàn)在來一起看下幾個(gè)場景:

  1. 在持久化時(shí), 程序崩潰了;
  2. 在持久化時(shí), 服務(wù)器崩潰了;
  3. 在持久化時(shí), 程序與DB的鏈接斷開了;
  4. 持久化使用了多線程, 線程A把線程B的持久化數(shù)據(jù)覆蓋了, 甚至最終持久化的數(shù)據(jù)有1/3是線程A的, 2/3是線程B的, 形成了數(shù)據(jù)混淆;
  5. 在數(shù)據(jù)讀取時(shí), 把持久化一半的記錄讀取出來了;
  6. etc;

正因?yàn)槲覀兊某绦蜻\(yùn)行的環(huán)境是不穩(wěn)定的, 所以上面的種種場景都在日常生產(chǎn)中可能遇到的;

而正因?yàn)橄到y(tǒng)的不穩(wěn)定了, 造成了原本預(yù)期結(jié)果是true | false, 結(jié)果返回的是未知狀態(tài), 因?yàn)槌绦虮紳⒘? 我也不知道持久化到哪部分?jǐn)?shù)據(jù)了; 也就是形成了三態(tài)問題;

那業(yè)務(wù)系統(tǒng)為了數(shù)據(jù)的可靠性, 能不能處理這個(gè)三態(tài)問題呢? 答案是能的, 但是這個(gè)成本是很高的, 需要在業(yè)務(wù)代碼中嵌入許多非業(yè)務(wù)相關(guān)的代碼來保證數(shù)據(jù)的完整性, 同時(shí)也需要非常多的測試來驗(yàn)證這個(gè)方案的可行性;

那么有沒有更好的解決方案呢?

業(yè)務(wù)系統(tǒng)原本的預(yù)期就是true | false, 那么只需要數(shù)據(jù)庫層面把中間態(tài)解決掉就可以了, 這也就引出了事務(wù)是什么以及做了什么:

事務(wù)把業(yè)務(wù)系統(tǒng)的同一批操作抽象為一個(gè)邏輯單元, 該邏輯單元的所有操作要么都成功(commit), 否則就是全部失敗(abort), 然后回滾(rollback), 不會(huì)出現(xiàn)中間態(tài);

這樣做的好處就是對(duì)業(yè)務(wù)系統(tǒng)的反饋只會(huì)是成功或者失敗;

2. 事務(wù)是怎么實(shí)現(xiàn)的?

說到事務(wù)就不得不提到他的四個(gè)特性了:

2.1 ACID

單機(jī)事務(wù)的特性:(詳見維基百科)

  • Atomicity(原子性):一個(gè)事務(wù)(transaction)中的所有操作,或者全部完成,或者全部不完成,不會(huì)結(jié)束在中間某個(gè)環(huán)節(jié)。事務(wù)在執(zhí)行過程中發(fā)生錯(cuò)誤,會(huì)被回滾(Rollback)到事務(wù)開始前的狀態(tài),就像這個(gè)事務(wù)從來沒有執(zhí)行過一樣。即,事務(wù)不可分割、不可約簡。
  • Consistency(一致性):在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預(yù)設(shè)約束觸發(fā)器、級(jí)聯(lián)回滾等。
  • Isolation(隔離性):數(shù)據(jù)庫允許多個(gè)并發(fā)事務(wù)同時(shí)對(duì)其數(shù)據(jù)進(jìn)行讀寫和修改的能力,隔離性可以防止多個(gè)事務(wù)并發(fā)執(zhí)行時(shí)由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。事務(wù)隔離分為不同級(jí)別,包括未提交讀(Read uncommitted)、提交讀(read committed)、可重復(fù)讀(repeatable read)和串行化(Serializable)。
  • Durability(持久性):事務(wù)處理結(jié)束后,對(duì)數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會(huì)丟失。

2.1 原子性解讀

看到原子性第一反應(yīng)其實(shí)多線程中的原子性: 保證一個(gè)操作是原子的, 該操作的中間態(tài)是對(duì)其他線程不可見的; 但是事務(wù)的原子性不是用來解決并發(fā)的, 并發(fā)性是由隔離性來保證;

原子性解決的是中間的態(tài)的問題, 事務(wù)中的一批寫操作在執(zhí)行到某一個(gè)寫時(shí), 因?yàn)榫W(wǎng)絡(luò)或者其他原因, 寫失敗了, 那么該事務(wù)就應(yīng)該被中止, 并且數(shù)據(jù)庫必須撤銷該事務(wù)迄今為止所有的寫入;

所以原子性更多的是約束了事務(wù)可以中止的, 并且中止的時(shí)候會(huì)撤銷所有該事務(wù)未提交的寫入操作;

2.2 一致性解讀

一致性必須要說一下, 一致性這個(gè)詞在不同的語境中, 被賦予了不同含義:

  1. 在討論數(shù)據(jù)庫HA的時(shí)候主從復(fù)制的一致性, 或者異步復(fù)制的最終一致性, 這里強(qiáng)調(diào)的是兩個(gè)數(shù)據(jù)的值是相同的;
  2. 在CAP中的一致性, 指的是線性一致, 這個(gè)后面會(huì)講;

而事務(wù)的一致性怎么解讀呢?

維基百科中的解釋是: 在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞;

數(shù)據(jù)庫的完整性怎么理解? 就是持久的數(shù)據(jù)是符合我們的一定的預(yù)期的, 而這個(gè)預(yù)期在后續(xù)的寫入中沒有被破壞掉, 也就是我們對(duì)持久化的數(shù)據(jù)的預(yù)期是始終成立的; 而維基百科中提到的約束, 觸發(fā)器等都是來保證我們的這種預(yù)期始終成立;

看到這里, 是不是發(fā)現(xiàn)數(shù)據(jù)庫的一致性其實(shí)是由應(yīng)用程序來定義的, 什么數(shù)據(jù)是有效的, 而什么數(shù)據(jù)是無效的, 數(shù)據(jù)庫純粹只是用來持久化數(shù)據(jù)的;

2.3 持久性解讀

數(shù)據(jù)庫的持久性其實(shí)就是找個(gè)地方存儲(chǔ)數(shù)據(jù), 保證事務(wù)完成以后, 這部分已經(jīng)持久化的數(shù)據(jù)不會(huì)丟失; 在單機(jī)事中, 持久性說的是,只有當(dāng)該事務(wù)中的所有寫入操作的數(shù)據(jù)都已經(jīng)落盤了, 事務(wù)才會(huì)提交成功; 如果是數(shù)據(jù)庫集群, 表示這部分?jǐn)?shù)據(jù)已經(jīng)復(fù)制到了一些節(jié)點(diǎn)上;

但是單機(jī)事務(wù), 并不能完美保證這部分?jǐn)?shù)據(jù)不丟失, 比如你這機(jī)房被炸了, 你的數(shù)據(jù)也就丟了, 所有才有多副本存儲(chǔ)的; 但是多副本也只是降低了數(shù)據(jù)丟失的概率;

2.4 隔離性解讀

隔離性放到最后是因?yàn)檫@個(gè)比較復(fù)雜, 并且內(nèi)容也比較多; 隔離性可以簡單的分為兩類: 弱隔離級(jí)別和強(qiáng)隔離級(jí)別; 我們先來說說日常生產(chǎn)中用的比較多的弱隔離級(jí)別:

2.4.1 弱隔離級(jí)別

為什么說弱隔離性在生產(chǎn)中比較常見的呢? 因?yàn)槲覀內(nèi)粘=佑|的大部分都是讀多寫少的業(yè)務(wù); 也就是兩個(gè)事務(wù)大部分情況下是并行執(zhí)行的, 不會(huì)產(chǎn)生數(shù)據(jù)競爭, 這種場景下弱隔離級(jí)別就十分有用了;

2.4.1.1讀已提交

讀已提交的隔離級(jí)別是我們最常用到的, 因?yàn)樗WC了:

  1. 單個(gè)事務(wù)只能讀取其他事務(wù)已經(jīng)提交的數(shù)據(jù)(保證了沒有臟讀);
  2. 單個(gè)事務(wù)只能覆蓋其他事務(wù)已經(jīng)提交的數(shù)據(jù)(保證了沒有臟寫);

說一下臟讀和臟寫:

  1. 臟讀很好理解: 就是讀取了其他事務(wù)還未提交的數(shù)據(jù); 為什么要防止臟讀其實(shí)最大的原因是如果另一個(gè)事務(wù)中止了, 需要做回滾, 但是因?yàn)槟惝?dāng)前事務(wù)已經(jīng)讀取了回滾事務(wù)操作的數(shù)據(jù), 當(dāng)前事務(wù)的提交將導(dǎo)致回滾是無效的;
  2. 臟寫: 臟寫就是如果一個(gè)事務(wù)寫入了數(shù)據(jù), 但是還未提交事務(wù), 但是已經(jīng)被另一個(gè)事務(wù)的寫入給覆蓋了; 臟寫問題更嚴(yán)重, 舉個(gè)例子: 小明和小紅同時(shí)編輯同一個(gè)文章, 我們來看一下臟寫的問題:

<colgroup><col span="1" width="426"><col span="1" width="426"></colgroup>

小明 小紅
begin transaction Begin transaction;
Select article; Select article;
update title = '小明';
update title = '小紅';
Update author = '小紅';
Commit transaction;
Update author = '小明';
Commit transaction;

最終的結(jié)果會(huì)變成title是小紅, author是小明, 可以看到如果有臟寫, 來自不同事務(wù)的沖突, 導(dǎo)致數(shù)據(jù)被混淆了;

2.4.1.2 讀已提交的實(shí)現(xiàn)

  1. 臟寫的防止: 寫入需要獲取操作對(duì)象的鎖, 當(dāng)該對(duì)象鎖被其他事務(wù)占有時(shí), 當(dāng)前事務(wù)必須等待, 直到事務(wù)完成或中止時(shí)才釋放鎖;
  2. 臟讀的防止: 一種方式是讀也需要申請(qǐng)鎖, 如果該對(duì)象已經(jīng)被其他事務(wù)鎖定了, 當(dāng)前事務(wù)需要等待; 但是讀鎖的釋放是在讀取完成之后立即釋放的; 這種方式其實(shí)并不好, 因?yàn)橹灰嬖谝粋€(gè)寫入的長事務(wù), 必然會(huì)阻塞其他只讀事務(wù); 所有就有了方式二: 既然只需讀取其他事務(wù)已提交的數(shù)據(jù), 那么只要讀取當(dāng)前事務(wù)寫入前的數(shù)據(jù)就可以了; 這種方式就是當(dāng)有寫入事務(wù)正在執(zhí)行的時(shí)候, 數(shù)據(jù)庫會(huì)做一個(gè)快照保存當(dāng)前寫入事務(wù)寫入前的值, 當(dāng)有讀取事務(wù)進(jìn)來時(shí), 只需要讀取快照即可;只有當(dāng)寫入事務(wù)提交了, 讀取事務(wù)才會(huì)去讀取最新值;
  3. 所以讀已提交的實(shí)現(xiàn), 讀不阻塞寫, 寫不阻塞讀;

讀已提交存在的問題

讀已提交隔離級(jí)別看上去已經(jīng)十分美好了: 因?yàn)樗瑫r(shí)防止了臟讀和臟寫, 但是我們來看下這個(gè)例子:

拿用戶購買基金以后, 需要扣賬戶余額與加資產(chǎn)舉例(假設(shè)賬戶表與資產(chǎn)表都在同一個(gè)DB上):

<colgroup><col span="1" width="426"><col span="1" width="426"></colgroup>

投資事務(wù) 查詢事務(wù)
Begin transaction
Select position;(1000)
Begin transaction;
update account = 500;
update position = 1500;
Commit transaction
select account;(500)
Commit transaction

因?yàn)槭亲x已提交的隔離級(jí)別, 所以在投資事務(wù)未提交前, 用戶先看了下資產(chǎn)數(shù)據(jù), 只有1000, 在投資事務(wù)提交以后, 用戶看了賬戶余額是500, 導(dǎo)致用戶以為自己少了500的資產(chǎn);

這種問題被稱為不可重復(fù)讀, 這種問題在我們業(yè)務(wù)上其實(shí)也是存在的, 比如需要查詢并進(jìn)行校驗(yàn)的時(shí)候, 一個(gè)長事務(wù)的兩次讀取可能會(huì)讀取到不同的值, 導(dǎo)致本次操作失敗的問題;

2.4.1.3 不可重復(fù)讀的解決方案(可重復(fù)讀)

這個(gè)問題還是讀寫并發(fā)的問題, 在不考慮加鎖的情況下, 可以參考讀已提交的快照隔離來實(shí)現(xiàn):讀已提交的實(shí)現(xiàn)是考慮了寫事務(wù)包了讀事務(wù)的時(shí)候, 怎么來處理臟讀; 不可重復(fù)的問題是讀事務(wù)包了寫事務(wù);那么只保留一份快照是不可取的, 因?yàn)橐粋€(gè)讀事務(wù)可能會(huì)包掉多個(gè)寫事務(wù), 會(huì)導(dǎo)致連快照都已經(jīng)被覆蓋的情況; 所以不可重復(fù)讀的解決方案就是保存多份數(shù)據(jù)快照:這種方案也就是MVCC(多版本并發(fā)控制);

MVCC實(shí)現(xiàn)快照隔離

數(shù)據(jù)庫會(huì)默認(rèn)給每張表加上兩個(gè)屬性: created_by 和 deleted_by, 這兩個(gè)屬性分別寫入的是該條記錄是由哪個(gè)事務(wù)創(chuàng)建的(created_by), 由哪個(gè)事務(wù)更新的(deleted_by), 每次新建事務(wù)的時(shí)候數(shù)據(jù)庫會(huì)默認(rèn)分配事務(wù)ID;

  1. insert 只會(huì)寫入created_by;
  2. Delete 會(huì)寫入deleted_by;
  3. update會(huì)被解析為 delete + insert;

怎么通過created_by 和 deleted_by來實(shí)現(xiàn)可重復(fù)讀呢?
多版本控制類似于下面的存儲(chǔ):

<colgroup><col span="1" width="284"><col span="1" width="284"><col span="1" width="284"></colgroup>

data created_by deleted_by
A 4
D 3 4
C 2 3
B 1 2
A 0 1

Deleted_by只有事務(wù)真正提交時(shí)才會(huì)生成快照, 也就是所有中止操作都不會(huì)生成快照;

只要在該事務(wù)開始前的快照, 都是對(duì)該事務(wù)可見的; 在該事務(wù)開始后的快照, 對(duì)該事務(wù)是不可見的;
通過deleted_by關(guān)聯(lián)created_by可以找到該個(gè)事務(wù)之前所有的快照, 那么可以通過[delete_by, created_by]這個(gè)區(qū)間來判斷, 當(dāng)前需要讀取哪份快照了;
我們通過前面的購買基金的例子來說明:(假設(shè)account和position的created_by為0)

<colgroup><col span="1" width="213"><col span="1" width="213"><col span="1" width="213"><col span="1" width="213"></colgroup>

投資事務(wù)1 讀取事務(wù)1 投資事務(wù)2 讀取事務(wù)2
Begin;t_id = 1;
Begin;t_id = 2; select account = 1000;
update account = 500;
Udpdate position = 1500;
Commit;
Begin;t_id = 3; Begin;t_id = 4;
Update account = 1000; Select account = 500;
select position = 1000;select account = 1000; commit; Select account = 500;
Commit; commit;

account最終的快照:

<colgroup><col width="284" span="1"><col width="284" span="1"><col width="284" span="1"></colgroup>
| account | create_by | deleted_by |
| 1000 | 3 | |
| 500 | 2 | 3 |
| 1000 | 0 | 2 |

position最終的快照:

<colgroup><col span="1" width="284"><col span="1" width="284"><col span="1" width="284"></colgroup>

position created_by deleted_by
1500 2
1000 0 2

先來看讀取事務(wù)2: 該條事務(wù)開始時(shí), 數(shù)據(jù)庫會(huì)先列出當(dāng)前所有還未提交的事務(wù)集合[1,3,4], 然后再判斷account的當(dāng)前快照[0,2], 因?yàn)?>2, 所以第一次讀取到的是500; 第二次讀取的時(shí)候, 因?yàn)槭聞?wù)3已經(jīng)提交了, 所以當(dāng)前account的快照是[0-3], 如果這個(gè)時(shí)候僅僅只是判斷4>3, 那讀取到的應(yīng)該是1000; 但是因?yàn)樵谑聞?wù)開始的時(shí)候已經(jīng)記錄了[1,3,4]是還未提交的, 所以應(yīng)該過濾掉事務(wù)3提交所產(chǎn)生的快照, 所以第二次讀取的仍然是500;

2.4.1.4 寫并發(fā)引發(fā)的問題

快照隔離主要解決是讀寫并發(fā)時(shí), 只讀事務(wù)能看到什么, 但是還有一種情形其實(shí)也是很常見的, 那就是寫寫并發(fā)了, 比如金融場景中很常見的加資產(chǎn): 如果一個(gè)用戶購買了2個(gè)產(chǎn)品, 需要給他加2次資產(chǎn), 并更新總資產(chǎn)值;

<colgroup><col span="1" width="426"><col span="1" width="426"></colgroup>

事務(wù)1 事務(wù)2
Begin; Begin;
select position = 600;
Update position = 1100; select position = 600;
Commit; Update position = 1100;
commit;

不管是讀已提交或者是可重復(fù)讀這種場景都是正常, 但是當(dāng)這兩個(gè)事務(wù)提交完成以后, 用戶會(huì)發(fā)現(xiàn)自己賬戶少了500的資產(chǎn), 為什么呢, 因?yàn)槭聞?wù)2把事務(wù)1的結(jié)果覆蓋了, 這種情況叫丟失更新;

如何避免呢?

  1. 原子寫, update position = position + 500; 現(xiàn)在數(shù)據(jù)庫基本都支持這種原子寫了;
  2. 顯示鎖定: select for update;
  3. CAS: 加樂觀鎖 update position = 1100 where position = 600;

還有一種更神奇的場景: 當(dāng)我們需要在一個(gè)事務(wù)里操作多個(gè)對(duì)象的時(shí)候, 比如購買產(chǎn)品需要先扣余額, 再加資產(chǎn);

賬戶初始金額是1000;

<colgroup><col span="1" width="426"><col span="1" width="426"></colgroup>

事務(wù)1 事務(wù)2
Begin; Begin;
Select account = 1000;
if(account > 0) then; Select account = 1000;
update account = 0; if(account > 0) then;
update position = position + 1000; update account = 0;
commit; update position = position + 1000;
commit;

在事務(wù)中先判斷余額是否足夠, 如果單個(gè)事務(wù)執(zhí)行, 上面的邏輯沒有任何問題; 但是當(dāng)兩個(gè)事務(wù)并發(fā)的時(shí)候, 只要有一個(gè)事務(wù)生效了, 另一個(gè)事務(wù)的前提其實(shí)已經(jīng)不滿足了, 但是現(xiàn)在并發(fā)的結(jié)果是, 明明只有1000塊, 卻購買了2000塊的產(chǎn)品并成功加了資產(chǎn); 這種問題為寫偏差, 也稱為幻讀, 寫偏差的類型其實(shí)很好總結(jié)的:

  1. select符合條件的記錄, 然后做判斷;
  2. 如果第一個(gè)條件是滿足的, 就進(jìn)行后續(xù)寫入操作;

解決方案:

  1. 對(duì)先決條件加鎖, 即select for update;
  2. 有些場景里是沒法加鎖的, 比如用戶余額這種場景, 那這個(gè)時(shí)候怎么辦呢? 我們可以人為的在數(shù)據(jù)庫中引入一個(gè)可加鎖的對(duì)象, 比如扣款申請(qǐng)單, 那么用戶加資產(chǎn)就可以拆分為 扣余額 和 加資產(chǎn)兩個(gè)不同的事務(wù), 每個(gè)事務(wù)都可以引入原子寫了;

當(dāng)然 以上兩個(gè)問題都可以用串行化的隔離級(jí)別來搞定, 但是這個(gè)隔離級(jí)別效率實(shí)在太低了;

2.4.2 強(qiáng)隔離級(jí)別

只有串行化(Serializable)是強(qiáng)隔離性的, 字面意思就是如果事務(wù)并發(fā)了, 一個(gè)時(shí)間點(diǎn)只會(huì)有一個(gè)事務(wù)在運(yùn)行, 其他都需要等待, 正因?yàn)榇谢瘓?zhí)行, 性能非常低, 所有在實(shí)踐中運(yùn)用的比較少, 甚至于有些數(shù)據(jù)庫, 比如Oracle中壓根就沒實(shí)現(xiàn), 雖然有可序列化這個(gè)級(jí)別, 但是真正的實(shí)現(xiàn)確是快照隔離(在下面的弱隔離級(jí)別中會(huì)討論);

2.4.2.1 2PL

兩階段鎖(注意不是2階段提交): 即當(dāng)多個(gè)事務(wù)操作需要寫入同一個(gè)對(duì)象時(shí)(修改或刪除), 需要單獨(dú)占有這個(gè)對(duì)象(可以理解為JAVA中的獨(dú)占鎖):

  1. 如果對(duì)象A已經(jīng)被事務(wù)1讀取了, 這時(shí)候事務(wù)B需要操作對(duì)象A, 必須等事務(wù)A提交或者終止;
  2. 如果對(duì)象A已經(jīng)被事務(wù)1操作了, 這時(shí)候事務(wù)B需要讀取對(duì)象A, 必須等事務(wù)A提交或者終止;

所以兩階段鎖是即阻塞讀也阻塞寫, 來保證沒有臟讀與臟寫;

2PL的實(shí)現(xiàn)

2PL的實(shí)現(xiàn)主要是通過對(duì)數(shù)據(jù)庫中每個(gè)對(duì)象加鎖來實(shí)現(xiàn)的, 鎖分為共享模式和獨(dú)占模式;

  1. 事務(wù)會(huì)以共享鎖來讀取對(duì)象, 但是如果這個(gè)對(duì)象已經(jīng)被其他事務(wù)使用獨(dú)占鎖鎖定了, 則當(dāng)前的讀事務(wù)必須等待;
  2. 事務(wù)需要操作對(duì)象時(shí), 必須獲取獨(dú)占鎖; 但是如果當(dāng)前對(duì)象已經(jīng)有其他事務(wù)獲取了共享鎖或者獨(dú)占鎖, 則當(dāng)前事務(wù)必須等待;
  3. 事務(wù)先以共享鎖讀取了對(duì)象, 但是寫入對(duì)象時(shí), 需要將共享鎖升級(jí)為獨(dú)占鎖; 鎖升級(jí)過程與獲取獨(dú)占鎖一致;
  4. 事務(wù)獲取鎖以后, 必須持有至事務(wù)結(jié)束(commit | abort)才能釋放鎖; 這也是兩階段鎖的名稱來源: 一階段(事務(wù)開始或者執(zhí)行時(shí))獲取鎖, 二階段(事務(wù)結(jié)束)釋放鎖;

既然用到了鎖, 且一個(gè)事務(wù)中可能需要去獲取多把鎖, 那么就很有可能發(fā)生死鎖: 事務(wù)A持有A對(duì)象的鎖, 需要去獲取B對(duì)象的鎖, 但是事務(wù)B已經(jīng)持有了B對(duì)象的鎖, 需要去獲取A對(duì)象的鎖, 這個(gè)時(shí)候就會(huì)發(fā)生死鎖;

死鎖發(fā)生以后, 數(shù)據(jù)庫會(huì)自動(dòng)檢測并中止其中一個(gè)事務(wù), 以便讓另一個(gè)事務(wù)繼續(xù)進(jìn)行, 中止的事務(wù)的重試有應(yīng)用系統(tǒng)完成;這也是兩階段鎖效率低下的一個(gè)原因;

2.4.3 串行化快照隔離(SSI)

弱隔離級(jí)別會(huì)有臟讀, 不可重復(fù)讀, 幻讀等問題, 但是采用強(qiáng)隔離級(jí)別就會(huì)有性能問題, 那么有沒有一種方案能兼容這兩者的優(yōu)點(diǎn)呢?那就是2008年才被提出來的串行化快照隔離;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容