savepoint是事务内部允许部分rollback的标志符。因为事务中对记录做了修改,我们可以在事务中创建savepoint来标识不同的点。如果遇到错误,就可以rollback到不同的点或直接回来事务最开始的点。
SAVEPOINT和ROLLBACK TO SAVEPOINT语法:
SAVEPOINT identifier
ROLLBACK [WORK] TO SAVEPOINT identifier
RELEASE SAVEPOINT identifier
例子:
create table t(id number,name varchar2(10));
//创建savepoint t1
insert into t values (1,'Tough1');
savepoint t1;//创建savepoint t2
insert into t values (2,'Tough2');
savepoint t2;//创建savepoint t3
update t set name='Tough' where id=2;
savepoint t3;//回滚到update之前的状态,savepoint t3丢失
rollback to savepoint t2;//回到第一个insert之前的状态,即空表。
rollback;//如果执行COMMIT,当前事务的所有保存点被删除
commit;delete from t where id=1;
savepoint t4;//COMMIT后,当前事务的所有保存点被删除。rollback时出现错误。
//ORA-01086: 从未创建保存点 'T3'
rollback to savepoint t3;
Savepoints在应用程序中同样有用。如果一个过程包含几个函数,那可以在每个函数前创建一个savepoint。如果一个函数失败,返回数据到函数开始前的状态并在修改参数或执行一个恢复操作后重新运行函数就非常容易。
在回滚到一个savepoint后,Oracle释放由被回滚的语句持有的锁。其他等待之前被锁资源的事务可以进行了。其他要更新之前被锁行的事务也可以执行。
当一个事务回滚到一个savepoint,发生下列事件:
1. Oracle仅回滚savepoint之后的语句。
2. Oracle保留这一savepoint,但所有建立于此后的savepoints丢失。
3. Oracle释放在该savepoint后获得的所有表、行锁,但保留之前获得的所有锁。
4. 事务保持活动并可继续。
无论何时一个会话在等待事务,到savepoint的回滚不会释放行锁。为了确保事务如果无法获得锁也不会悬挂(hang),在执行UPDATE或DELETE前使用FOR UPDATE ... NOWAIT。(这里指回滚的savepoint之前获得的锁。该savepoint后获得的行锁会被释放,之后执行的语句也会被彻底回滚。)
如果执行COMMIT,当前事务的所有保存点被删除。rollback时出现错误-ORA-01086: 从未创建保存点 'T3'。