事務(wù)是數(shù)據(jù)庫系統(tǒng)的基礎(chǔ)概念。
事務(wù)本質(zhì)上有四個(gè)特點(diǎn) —— ACID:
Atomicity 原子性
原子性體現(xiàn)在對于一個(gè)事務(wù)來講,必須要以一個(gè)整體單元的形式進(jìn)行工作。對于數(shù)據(jù)的修改,要么全部執(zhí)行,要么全部不執(zhí)行。出錯(cuò)必須回滾到先前的狀態(tài)。Consistency 一致性
一個(gè)事務(wù)可以封裝狀態(tài)改變(除非它是一個(gè)只讀的)。事務(wù)必須始終保持系統(tǒng)處于一致的狀態(tài),不管在任何給定的時(shí)間并發(fā)事務(wù)有多少。
一致性有下面特點(diǎn):
- 如果一個(gè)操作觸發(fā)輔助操作(級聯(lián),觸發(fā)器),這些也必須成功,否則交易失敗。
- 如果系統(tǒng)是由多個(gè)節(jié)點(diǎn)組成,一致性規(guī)定所有的變化必須傳播到所有節(jié)點(diǎn)(多主復(fù)制)。如果從站節(jié)點(diǎn)是異步更新,那么我們打破一致性規(guī)則,系統(tǒng)成為“最終一致性”。
- 一個(gè)事務(wù)是數(shù)據(jù)狀態(tài)的切換,因此,如果事務(wù)是并發(fā)多個(gè),系統(tǒng)也必須如同串行事務(wù)一樣操作。
- 在現(xiàn)實(shí)中,事務(wù)系統(tǒng)遭遇并發(fā)請求時(shí),這種串行化是有成本的, Amdahl法則描述如下:它是描述序列串行執(zhí)行和并發(fā)之間的關(guān)系。“一個(gè)程序在并行計(jì)算情況下使用多個(gè)處理器所能提升的速度是由這個(gè)程序中串行執(zhí)行部分的時(shí)間決定的。” 大多數(shù)數(shù)據(jù)庫管理系統(tǒng)選擇(默認(rèn)情況下)是放寬一致性,以達(dá)到更好的并發(fā)性。
Isolation 隔離性
事務(wù)是并發(fā)控制機(jī)制,他們交錯(cuò)使用時(shí)也能提供一致性。隔離讓我們隱藏來自外部世界未提交的狀態(tài)變化,一個(gè)失敗的事務(wù)不應(yīng)該破壞系統(tǒng)的狀態(tài)。隔離是通過用悲觀或樂觀鎖機(jī)制實(shí)現(xiàn)的。Durability 持久性
一個(gè)成功的事務(wù)將永久性地改變系統(tǒng)的狀態(tài),所以在它結(jié)束之前,所有導(dǎo)致狀態(tài)的變化都記錄在一個(gè)持久的事務(wù)日志中。如果我們的系統(tǒng)突然受到系統(tǒng)崩潰或斷電,那么所有未完成已提交的事務(wù)可能會重新執(zhí)行。
SQL標(biāo)準(zhǔn)規(guī)定了四個(gè)隔離級別:
- READ_UNCOMMITTED 讀未提交
- READ_COMMITTED 讀已提交
- REPETABLE_READ 可重復(fù)讀
- SERIALIZABLE 可序列化
隔離級別 | 臟讀 | 不可重復(fù)讀 | 幻讀 | 序列化異常 |
---|---|---|---|---|
READ_UNCOMMITTED | 允許 (PG中不允許) | 允許 | 允許 | 允許 |
READ_COMMITTED | 不允許 | 允許 | 允許 | 允許 |
REPETABLE_READ | 不允許 | 不允許 | 允許 (PG中不允許) | 允許 |
SERIALIZABLE | 不允許 | 不允許 | 不允許 | 不允許 |
臟讀
一個(gè)事務(wù)讀取了另一個(gè)并行未提交事務(wù)寫入的數(shù)據(jù)。不可重復(fù)讀
一個(gè)事務(wù)重新讀取之前讀取過的數(shù)據(jù),發(fā)現(xiàn)該數(shù)據(jù)已經(jīng)被另一個(gè)事務(wù)(在初始讀之后提交)修改。幻讀
一個(gè)事務(wù)重新執(zhí)行一個(gè)返回符合一個(gè)搜索條件的行集合的查詢, 發(fā)現(xiàn)滿足條件的行集合因?yàn)榱硪粋€(gè)最近提交的事務(wù)而發(fā)生了改變。序列化異常
成功提交一組事務(wù)的結(jié)果與這些事務(wù)所有可能的串行執(zhí)行結(jié)果都不一致。
PostgreSQL 中的事務(wù)
PostgreSQL事務(wù)的隔離級別目前有4種,分別是:讀未提交,讀已提交,可重復(fù)讀,串行化。在PostgreSQL里,你可以請求四種可能的事務(wù)隔離級別中的任意一種。但是在內(nèi)部, 實(shí)際上只有三種獨(dú)立的隔離級別,分別對應(yīng)讀已提交,可重復(fù)讀和可串行化。如果你選擇了讀未提交的級別, 實(shí)際上你用的是讀已提交,在重復(fù)讀的PostgreSQL執(zhí)行時(shí),幻讀是不可能的, 所以實(shí)際的隔離級別可能比你選擇的更嚴(yán)格。這是因?yàn)榘褬?biāo)準(zhǔn)隔離級別映射到 PostgreSQL 的多版本并發(fā)控制架構(gòu)的唯一合理的方法。
SQL 標(biāo)準(zhǔn)允許更嚴(yán)格的行為:四種隔離級別只定義了哪種現(xiàn)像不能發(fā)生,但是沒有定義哪種現(xiàn)像必須發(fā)生。某些PostgreSQL數(shù)據(jù)類型和函數(shù)關(guān)于事務(wù)的行為有特殊的規(guī)則。特別是,對一個(gè)序列的修改(以及用serial聲明的一列的計(jì)數(shù)器)是立刻對所有其他事務(wù)可見的,并且在作出該修改的事務(wù)中斷時(shí)也不會被回滾。
默認(rèn)情況下 PostgreSQL會將每一個(gè)SQL語句都作為一個(gè)事務(wù)來執(zhí)行。如果我們沒有發(fā)出BEGIN命令,則每個(gè)獨(dú)立的語句都會被加上一個(gè)隱式的BEGIN以及(如果成功)COMMIT來包圍它。一組被BEGIN和COMMIT包圍的語句也被稱為一個(gè)事務(wù)塊。
BEGIN;
UPDATE accounts SET balance = balance - 100.00
WHERE name = 'Alice';
COMMIT;
也可以利用保存點(diǎn)來以更細(xì)的粒度來控制一個(gè)事務(wù)中的語句。保存點(diǎn)允許我們有選擇性地放棄事務(wù)的一部分而提交剩下的部分。在使用SAVEPOINT定義一個(gè)保存點(diǎn)后,我們可以在必要時(shí)利用ROLLBACK TO回滾到該保存點(diǎn)。該事務(wù)中位于保存點(diǎn)和回滾點(diǎn)之間的數(shù)據(jù)庫修改都會被放棄,但是早于該保存點(diǎn)的修改則會被保存。
在回滾到保存點(diǎn)之后,它的定義依然存在,因此我們可以多次回滾到它。反過來,如果確定不再需要回滾到特定的保存點(diǎn),它可以被釋放以便系統(tǒng)釋放一些資源。記住不管是釋放保存點(diǎn)還是回滾到保存點(diǎn)都會釋放定義在該保存點(diǎn)之前的所有其他保存點(diǎn)。
所有這些都發(fā)生在一個(gè)事務(wù)塊內(nèi),因此這些對于其他數(shù)據(jù)庫會話都不可見。當(dāng)提交整個(gè)事務(wù)塊時(shí),被提交的動作將作為一個(gè)單元變得對其他會話可見,而被回滾的動作則永遠(yuǎn)不會變得可見。
BEGIN;
UPDATE accounts SET balance = balance - 100.00
WHERE name = 'Alice';
SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Bob';
-- oops ... forget that and use Wally's account
ROLLBACK TO my_savepoint;
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Wally';
COMMIT;
查看數(shù)據(jù)庫事務(wù)隔離級別
SELECT name, setting FROM pg_settings WHERE name ='default_transaction_isolation';
或
SELECT current_setting('default_transaction_isolation');
設(shè)置全局事務(wù)隔離級別
法一:
修改 postgresql.conf 文件中的 default_transaction_isolation
法二:
alter system set default_transaction_isolation to 'REPEATABLE READ';
查看當(dāng)前會話事務(wù)隔離級別
show transaction_isolation
或
SELECT current_setting('transaction_isolation');
設(shè)置當(dāng)前會話事務(wù)隔離級別
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
設(shè)置當(dāng)前事務(wù)的事務(wù)隔離級別
START TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
或
BEGIN ISOLATION LEVEL READ UNCOMMITTED READ WRITE;