Postgresql 事務(wù)總結(jié)
五種并發(fā)問題
丟失更新: 一個(gè)事務(wù)覆蓋另一個(gè)事務(wù)已提交的更新數(shù)據(jù).
dirty read: 一個(gè)事務(wù)讀取到另一個(gè)事務(wù)還沒提交的數(shù)據(jù).
repeatable read: 一個(gè)事務(wù)先后讀到另一個(gè)事務(wù)提交之前和之后的數(shù)據(jù).
phantom read: 事務(wù)在操作過程中進(jìn)行兩次查詢, 兩次結(jié)果不一樣.
-
serialization anomaly: 成功提交一組事務(wù)的結(jié)果與每次運(yùn)行這些事務(wù)的順序不一樣.
postgres的隔離級(jí)別
ioslate
如何理解事務(wù)呢?
舉個(gè)例子, 從A轉(zhuǎn)100元給B, 需要2條sql,
update account set balance = balance - 100 where name = 'A'
update account set balance = balance + 100 where name = 'B'
- 原子性
我們需要保證要么2個(gè)同時(shí)發(fā)生, 要么都不發(fā)生, 這就是由DB的事務(wù)來保證的. - 持久性
要在存入硬盤之后再告知成功. - 還有互斥性.
我在給A存錢的時(shí)候, 其它人不可以查A的余額, 不然會(huì)導(dǎo)致不一致.
如何加事務(wù)呢?
default, every single sql is a transaction, we also can use "begin" and "commit" to specific a transaction
BEGIN;
update account set balance = balance - 100 where name = 'A'
update account set balance = balance + 100 where name = 'B'
commit;
更細(xì)粒度可以用 savepoint 和rollback to 來控制.
BEGIN;
update account set balance = balance - 100 where name = 'A'
savepoint update_A_success;
update account set balance = balance + 100 where name = 'B'
rollback to update_A_success;
commit;
Demo
-
假設(shè)我們有個(gè)DB, 有個(gè)account表, 這個(gè)表只有名字和余額.
最開始我們只有一個(gè)叫bob的帳戶.
init -
現(xiàn)在我們?cè)谝粋€(gè)會(huì)話里開始一個(gè)事務(wù).
BEGIN;
INSERT INTO account(name,balance) VALUES('Alice',10000);
成功之后, 現(xiàn)在我們?cè)诋?dāng)前會(huì)話里可以查到alice, 但在其它會(huì)話里查不到.
直到我們commit, 其它會(huì)話才可以看到.