在PostgreSQL的psql中,如果执行一个dml或ddl语句,没有先运行begin;的话,一执行完就马上提交了,不能回滚,这样容易导致误操作的发生,避免这个风险的办法是关闭自动提交,方法如下:
设置\set AUTOCOMMIT off
testdb=# create table tt1(x int);
CREATE TABLE
Time: 0.593 ms
testdb=# select * from tt1;
x
---
(0 rows)
testdb=# rollback;
ROLLBACK
testdb=# select * from tt;
ERROR: relation "tt" does not exist
LINE 1: select * from tt;
^
Time: 0.376 ms
这儿我们需要注意的是,不同于Oracle,PG的DDL事务一样是可以回滚的,并没有隐式提交的概念
testdb=# \d
List of relations
Schema | Name | Type | Owner
--------+------+-------+-------
public | foo | table | kiwi
public | test | table | kiwi
(2 rows)
rollback的功能在数据库中都一样,未提交的操作都会回滚,在psql中默认配置下AUTOCOMMIT是打开的,这一点和oracle不同,
如果测试需要先把autocommit设置为off,
\set AUTOCOMMIT off
savepoint可以创建保存点,可以作为rollback的指向。
一个会话开启一个事务后,关闭事务自动提交,创建多个savepoint点,可以多次rollback到同一个savepoint,rollback至savepoint后可以继续操作,参考如下:
创建测试表
create table tt(id int);
testdb=# \set AUTOCOMMIT off #关闭自动提交
执行以下sql事务语句
begin;
insert into tt values(1);
insert into tt values(2);
savepoint savepoint1;
insert into tt values(3);
insert into tt values(4);
savepoint savepoint2;
insert into tt values(5);
insert into tt values(6);
testdb=# select * from tt;
t1
----
1
2
3
4
5
6
(6 rows)
testdb=# rollback to savepoint savepoint2; #回滚到保存点savepoint2 ,查看数据
ROLLBACK
testdb=# select * from tt;
t1
----
1
2
3
4
(4 rows)
testdb=# rollback to savepoint savepoint1; #回滚到保存点savepoint1,查看数据
ROLLBACK
testdb=# select * from tt;
id
----
1
2
(2 rows)
testdb=# insert into tt values(3);
INSERT 0 1
testdb=# insert into tt values(4);
INSERT 0 1
testdb=# select * from tt;
id
----
1
2
3
4
(4 rows)
2.在rollback至savepoint2后操作如果出错,后续的所有操作会报
ERROR: current transaction is aborted, commands ignored until end of transaction block
这时候需要再次rollback to savepoint2可以回滚至savepoint2。
testdb=# insert into tt values('dfsdfdsf','sdf');
ERROR: INSERT has more expressions than target columns
LINE 1: insert into tt values('dfsdfdsf','sdf');
^
testdb=# select * from tt;
ERROR: current transaction is aborted, commands ignored until end of transaction block
testdb=# \d tt
ERROR: current transaction is aborted, commands ignored until end of transaction block
testdb=# ;
testdb=# select * from tt;
ERROR: current transaction is aborted, commands ignored until end of transaction block
testdb=# rollback to savepoint savepoint2;
ROLLBACK
testdb=# select * from tt;
t1
----
1
2
3
4
(4 rows)
testdb=# commit; #如果此处执行手动提交事务,再执行回滚,会报错!!
COMMIT
testdb=# select * from tt;
id
----
1
2
3
4
(4 rows)
testdb=# rollback to savepoint savepoint1; #此处是回滚失败
ERROR: no such savepoint
STATEMENT: rollback to savepoint savepoint1;
ERROR: no such savepoint
结论:
1)PG的自动提交默认是开启状态,ddl语句也可以回滚操作,这两点和oracle有区别。
2)事务的提交与回滚体现事务的原子性特征,事务语句要么提交,要么回滚;
3)事务执行过程中可以任意创建保存点,根据需要执行回滚操作,如果不指定保存点,回滚操作会回滚到事务起始点,即begin开始的地方;
4)执行回滚操作在比较大的事务中,可以把执行过程分为几个步骤,每个步骤执行完成后创建一个保存点,后续步骤执行失败时,可回滚到之前的保存点,而不必回滚整个事务。
by 波罗