本章提要
------------------------------------------事务的特性事务控制语句------------------------------------------事务, 把数据库从一种一致状态转变为另一种一致状态.事务的特性: 1) 原子性, 事务所有动作要么都发生, 要么都不发生 2) 一致性, 事务将数据库从一种状态转变为下一种状态 3) 隔离性, 一个事务在该事务提交之前对其他事务都不可见 4) 持久性, 事务一旦提交, 其结果永久保留.事务的控制语句 1) commit, 结束你的事务,并将事务提交到online redo log file中(磁盘文件). 2) rollback, 结束你的事务, 并回滚, 为此要读取存储在回滚段/undo段中的信息, 并把数据库块恢复到事务开始 之前的状态. 3) savepoint, 在你的事务中创建一个标记点 4) rollback to <savepoint>, 可以把事务回滚到标记点, 而不回滚在此标记点之前的任何工作. 5) set transaction, 允许你设置不同事务属性, 例如隔离级别原子性 演示事务的原子性![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
create table t2( cnt int);insert into t2 values(0);commit;create table t ( x int check( x>0) );create trigger t_triggerbefore insert or delete on t for each rowbegin if (inserting) then update t2 set cnt = cnt + 1; else update t2 set cnt = cnt - 1; end if; dbms_output.put_line('I fired and updated' || sql%rowcount || 'rows');end;/-- testset serveroutput oninsert into t values(1);select * from t2; -- result : 1insert into t values(-1);select * from t2; -- result 还是 1, trigger中的output 已经正常输出了.-- oracle 保证最初的insert 语句是原子性的, 所以, 这个insert 语句应该与-- trigger 是在一个事务内, 而由于一个事务内的原子性特性, 外部insert语句-- 被回滚了, 所以trigger中的语句也被回滚了, 不过它确实被执行过了.
语句级原子性(实现模拟, 如下:) Savepoint statement1; insert into t values(1); if error then rollback to statement1; Savepoint statement2; insert into t values(-1); if error then rollback to statement2; 过程级原子性 oracle 把 PL/SQL 匿名块也当做是语句. 演示
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
/* * 例 1 * --------------------------------------------------------- */create or replace procedure pasbegin insert into t values(1); insert into t values(-1);end;/update t2 set cnt = 0;delete from t;commit;select * from t; -- now rows selectedselect * from t2; -- 0begin p;end;/-- 同样会得到错误提示select * from t; -- 0 rows selected-- 可见, 在匿名块中的两条Insert语句是一个事务, 具有原子性select * from t2; -- 0-- 另一种测试/* * 例2 * -------------------------------------------------------------------- */begin p;exception when others then dbms_output.put_line('Error!!!!' || sqlerrm );end;/-- 此时, t 和 t2 发生了变化, 因为第1条insert语句发生了作用-- 而此时, 由于捕获了异常, 所以系统并没有自动回滚, 而是等带你的操作-- 如果你 rollabck, 那么t中没有行 和 t2 是 0, 而如果你commit, 那么-- 第一条 insert 会对数据库产生影响. 从这个例子可以看出, p 中的每条语句具有语句级原子性-- 而匿名块具有事务级原子性.rollback;/* * 例 3 * --------------------------------------------------------------------- */begin savepoint sp; p;exception when others then rollback to sp; dbms_output.put_line('Error!!!!' || sqlerrm);-- 这样, 结果又是 0 了, 因为显示回滚到前面了
可见, 在一个存储过程内部的匿名块里的语句是具有相同的事务原子性. 启示: commit 或 rollback 一般情况下不应该出现在pl/sql块中, 只有pl/sql存储过程的调用者才知道事务何时完成. 匿名块内部的每条语句, 具有语句级原子性, 参看上边例子的后半段 ddl 语句具有自动提交, 并且具有事务级原子性, 比如: 演示
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
insert into t values(9);-- 注意, 此处并没有commitcreate table xxx(x int);-- 此时登陆别的session, 可以看到 9 这条记录已经插入了, 换句话说, 上边的-- insert 语句也已经提交了-- ddl 语句会自动提交, 事务级别的提交