基于Postgresql 事務(wù)的提交與回滾解析
用過(guò)oracle或mysql的基于ˉ\_(ツ)_/ˉ交人都知道在sqlplus或mysql中,做一個(gè)dml語(yǔ)句,事務(wù)如果發(fā)現做錯了,滾解還可以rollback;掉,基于交但在PostgreSQL的事務(wù)psql中,如果執行一個(gè)dml,滾解沒(méi)有先運行begin;的基于交話(huà),一執行完就馬上提交了,事務(wù)不能回滾,滾解??這(′▽?zhuān)?樣容易導??致誤操作的基于交發(fā)生,有沒(méi)有什么辦法避免這個(gè)風(fēng)險呢?事務(wù)
當然有,在psql中默認是滾解打開(kāi)自動(dòng)提交的,我們可以關(guān)閉自動(dòng)提交,基于交方法如下:
設置\set AUTOCOMMIT off
test=# crea(′▽?zhuān)?)te table test1 (x int);
CREATE TABLE
Time: 0.5(′?`)93 ms
test┐(′?`)┌=# select * from test1;
x
---
(0 rows)
Time: 0.309?? ms
test=# rollback;
ROLLBACK
Time: 1.501 ms
test=# select * from te(′-ι_-`)st1;
ERROR: relation "test1"?? does not exist
LINE 1: select * from test1;
^
Time: 0.376 ms
這兒我們需要注意的事務(wù)是,不同步Oracle,滾解PG的(de)DDL事務(wù)一樣是可以回滾的,并沒(méi)有隱式提交的概念,這兒我們需要注意下( ?° ?? ?°)
t??est=# \d
List of relations
Schema | Name | Type | Owner(′?`*)
--------+------+-------+-------
publ(??-)?ic | foo | table | kiwi
public | test | table | kiwi
(2 ro(?????)ws)
基本概念
事(shi)務(wù) Transac(′?_?`)tion 是 數據庫管理系統DBMS 執行過(guò)程中的一個(gè)邏輯單元,是一個(gè) sql命令組成的序列。
其特點(diǎn)在于,當事務(wù)被提交DBMS后,DBMS需要確保所有的操ヽ(′ー`)ノ作被完成;如果事務(wù)中有的操作沒(méi)有成功完成,那么所有操作都將回滾,回滾到事務(wù)提交之前??的狀態(tài)
屬性??
事務(wù)具有以下四個(gè)標準屬性
原子性:事務(wù)作為一個(gè)整體被執行,相當于一個(gè)原子
一致性:確保修改前后數據庫都滿(mǎn)足約束
隔離性:多個(gè)事務(wù)能(neng)并發(fā)執行,互不影響
持久性:已被提ヽ(′ー`)ノ交的事務(wù)對數據庫的修改應該永久保存在數據庫中ヽ(′▽?zhuān)?ノ
適用場(chǎng)景
某人在商店使用電子貨幣支付100元,包括以下兩個(gè)操作:
1. 消費者賬戶(hù)減少100元
2. 商家賬戶(hù)增加100元??
事務(wù)的作用就是保證這兩個(gè)操作要么都發(fā)生,要么都不發(fā)生,否則可能出現100元憑空消失。
事務(wù)控制
使用如下命令控制事務(wù)
begin 或者 begin transaction:開(kāi)始一個(gè)事務(wù)
commit 或者 end transaction:提交事務(wù),執行一系列sql
rollback:事務(wù)回滾
在開(kāi)始一個(gè)事務(wù)后,除非遇到 commit 或者 rollback 命令,事務(wù)才會(huì )被執行;
如果還沒(méi)遇到 commit 或者 rollback,數據庫發(fā)生異常,也會(huì )自動(dòng)回滾。
注意,事務(wù)命令只能用于 insert(′?ω?`)、delete、update 操作,而其他命令,比如建表、刪表,會(huì )被自動(dòng)提交。
總結一下:事務(wù)需要手動(dòng)開(kāi)啟,手動(dòng)提交;而且這種方式能提高操作效率。
實(shí)例
假設有如下表
id | name | age | address | salaヾ(′ω`)?ry
----(?_?;)+-------+-----+-----------+--------
1 | Paul | 32 | Califor??nia| 20000
2 | Allen?? | 25 | Texas | 15000
3 | Teddy | 23 | Norway | 20000
4 | Mark | 25 | Rich-Mond | 65000
5 | David | 27 | Texas | 85??000
6 | Kim | 22 | South-Hall|(′_`) 45000
7 | James | 24 | Houston | 10000
操作1:開(kāi)始事務(wù),從表中刪除年齡為25的記錄,最后用rollback撤銷(xiāo)所有操作
id | name | age | address | salary
----+-------+-(╬ ò﹏ó)----ヽ(′ー`)ノ+??--------(╯‵□′)╯---+--------
1 | Paul | 32 | California| 20000
2 | Allen | 25 | Texa??s | 15000
3 | Teddy | 23 | Norway | 20000
4 | Mark | 25 | Rich-Mond | 65000
5 | David | 27 | Texas | 85000
6 | Kim | 22 | South-Hall| 45000
7 | James | 24 | Houston | 10000
操作2:開(kāi)??始事務(wù),從表中刪除年齡為25的記錄,最后用(′ω`*)commit提交事務(wù)
runoobdb=#ヾ(′▽?zhuān)?? BEGIN;
DELETE FROM COMPANY WHER??E AGE = 25;
COMMIT;
Python 示例
time.clock??(??)
conn = psycopg2.connect(host='172.16( ?° ?? ?°).89.80',user="postgres",password='postgres',databaseヽ(′ー`)ノ=??"postgres")
cur = conn.cursor()
cur.execute("BEGIN TRANSACTION") # 開(kāi)始事務(wù)
if __name__=='__main__':
for i in range(0,1000):
cur.execヽ(′▽?zhuān)?/ute('INSERT INTO test(a, b, c, d) VALUES (%d, %d, %d, %d);'%(i, i, i, i))
cur.execute('commit') # 提交事務(wù)
cur.close()
conn.close()
print(time.clock())
繼續嘗試
上面手動(dòng)開(kāi)始了事務(wù)(wu),后面我做了如下嘗試,發(fā)現耗時(shí)只有 1s 【commit 優(yōu)化】
time.clock()
conn = psycopg2.co(′?_?`)nnect(host='172.1(′?`)6.89.80',user='??postgres',passwヾ(′?`)?ord="pos( ?▽?)tgres",da(°ロ°) !tabase="postg┐(′?`)┌res")
cur = conn.cur(′ω`)sor()
if __name__=='__ma(′ω`)in__':
for i in range(0,1000):
cur.execute('INSERT INTO test(a, b, c, d) VALUES (%d, %d(′ω`), %d, %d);'%(i, i, i, i))??
conn.commit()
cur.close()
conn.close()
print(time.clock()
執行(xing)了一系列sql,最后來(lái)個(gè) commit,同樣(╯°□°)╯執行成功,且耗時(shí)更少,我猜測是python自動(dòng)開(kāi)始了(′;ω;`)事務(wù),以 commit 命令提交,無(wú)需手動(dòng)開(kāi)始?!竞罄m有空會(huì )驗證(zheng)下這個(gè)猜測】
文章來(lái)源:腳本之家





