Oracle事务的ACID特性
原子性Atomicity:事务中的所有动作要么都发生,要么都不发生。 |
一致性Consistency:事务将数据库从一种状态转变为下一种一致状态。 |
隔离性Isolation:一个事务的影响在该事务提交前对其他事务时不可见的。 |
持久性Durability:事务一旦提交,其影响就是永久性的。 |
事务控制语句
事务隐式开始
事务必须显示结束(Commit、Rollback)
Commit 会结束事务,并使得已做的修改持久的保存在数据库中 |
Rollback 会结束事务,并撤销这个事务所做的修改。撤销动作需要读取回滚段中的信息,并把数据恢复到事务开始之前的状态 |
Savepoint 创建标记点(marked point),一个事务可以有多个标记点 |
Rollback To<Savepoint> 把事务回滚到指定的标记点,但是不回滚此标记点之前的工作。 |
Set transaction 允许设置不同的事务属性,如事务的隔离级别以及事务时只读的还是可读可写的。 |
原子性
语句级原子性 SQL> create table t2(cnt int); Table created. SQL> insert into t2 values(0); 1 row created. SQL> create table t(x int check(x>0)); Table created. SQL> create or replace trigger t_trigger 2 before insert or delete on t for each row 3 begin 4 if ( inserting ) then 5 update t2 set cnt=cnt+1; 6 else 7 update t2 set cnt=cnt-1; 8 end if; 9 dbms_output.put_line('I fired and updated'||sql%rowcount||'rows'); 10 end; 11 / SQL> set serveroutput on SQL> select * from t2; CNT ---------- 0 SQL> select * from t; no rows selected SQL> insert into t values(1); I fired and updated1rows 1 row created. SQL> insert into t values(-1); I fired and updated1rows insert into t values(-1) * ERROR at line 1: ORA-02290: check constraint (EODA.SYS_C007120) violated SQL> select * from t2; CNT ---------- 1
|
过程级原子性 Oracle把PL/SQL匿名块也当做是语句 SQL> create or replace procedure p 2 as 3 begin 4 insert into t values(1); 5 insert into t values(-1); 6 end; 7 / Procedure created. SQL> delete from t; 0 rows deleted. SQL> update t2 set cnt=0; 1 row updated. SQL> commit; Commit complete. SQL> select * from t; no rows selected SQL> select * from t2; CNT ---------- 0 SQL> begin 2 p; 3 end; 4 / begin * ERROR at line 1: ORA-02290: check constraint (EODA.SYS_C007120) violated ORA-06512: at "EODA.P", line 5 ORA-06512: at line 2 SQL> set serveroutput on SQL> / I fired and updated1rows I fired and updated1rows begin * ERROR at line 1: ORA-02290: check constraint (EODA.SYS_C007120) violated ORA-06512: at "EODA.P", line 5 ORA-06512: at line 2 SQL> select * from t; no rows selected SQL> select * from t2; CNT ---------- 0
|
事务级原子性 |
DDL与原子性 |
持久性
COMMIT的WRITE扩展 COMMIT WRITE WAIT (默认)必须等待redo写到磁盘才返回消息给客户端 COMMIT WRITE NOWAIT 异步提交,redo条目还没写入磁盘就返回消息给客户端 |
非分布式PL/SQL代码块中的COMMIT 在后台以异步的方式执行 即commit=commit write nowait |
完整性约束和事务
Immediate约束 整个SQL语句得到处理后立即检查 SQL> create table t(x int unique); Table created. SQL> insert into t values(1); 1 row created. SQL> insert into t values(2); 1 row created. SQL> commit; Commit complete. SQL> update t set x=x-1; 2 rows updated. |
Deferrable约束和级联更新 SQL> create table parent 2 (pk int primary key) 3 / Table created. SQL> create table child 2 (fk constraint child_fk_parent 3 references parent(pk) 4 deferrable 5 initially immediate 6 ) 7 / Table created. SQL> insert into parent values(1); 1 row created. SQL> insert into child values(1); 1 row created. SQL> update parent set pk=2; update parent set pk=2 * ERROR at line 1: ORA-02292: integrity constraint (EODA.CHILD_FK_PARENT) violated - child record found 由于约束是IMMEDIATE模式,update失败,换为deferred模式 SQL> set constraint child_fk_parent deferred; Constraint set. SQL> update parent set pk=2; 1 row updated. SQL> set constraint child_fk_parent immediate; set constraint child_fk_parent immediate * ERROR at line 1: ORA-02291: integrity constraint (EODA.CHILD_FK_PARENT) violated - parent key not found SQL> update child set fk=2; 1 row updated. SQL> set constraint child_fk_parent immediate; Constraint set. SQL> commit; Commit complete.
|
不好的事务习惯
在循环中提交 1.性能影响 SQL> create table t as select * from all_objects; Table created. SQL> exec dbms_stats.gather_table_stats(user,'T'); PL/SQL procedure successfully completed. SQL> variable n number SQL> exec :n:=dbms_utility.get_cpu_time; PL/SQL procedure successfully completed. SQL> update t set object_name=lower(object_name); 17977 rows updated. SQL> exec dbms_output.put_line((dbms_utility.get_cpu_time-:n)||' cpu hsecs...'); 25 cpu hsecs... PL/SQL procedure successfully completed. | SQL> exec :n:=dbms_utility.get_cpu_time; PL/SQL procedure successfully completed. BEGIN FOR x IN (SELECT ROWID rid, object_name, ROWNUM r FROM t) LOOP UPDATE t SET object_name = LOWER (x.object_name) WHERE ROWID = x.rid; IF (MOD (x.r, 100) = 0) THEN COMMIT; END IF; END LOOP; COMMIT; END; / PL/SQL procedure successfully completed. SQL> exec dbms_output.put_line((dbms_utility.get_cpu_time-:n)||' cpu hsecs...'); 108 cpu hsecs... PL/SQL procedure successfully completed.
| SQL> exec :n:=dbms_utility.get_cpu_time; PL/SQL procedure successfully completed.
DECLARE TYPE ridArray IS TABLE OF ROWID; TYPE vcArray IS TABLE OF t.object_name%TYPE; l_rids ridArray; l_names vcArray; CURSOR c IS SELECT ROWID, object_name FROM t; BEGIN OPEN c; LOOP FETCH c BULK COLLECT INTO l_rids, l_names LIMIT 100; FORALL i IN 1 .. l_rids.COUNT UPDATE t SET object_name = LOWER (l_names (i)) WHERE ROWID = l_rids (i); COMMIT; EXIT WHEN c%NOTFOUND; END LOOP; CLOSE c; END; / PL/SQL procedure successfully completed. SQL> exec dbms_output.put_line((dbms_utility.get_cpu_time-:n)||' cpu hsecs'); 26 cpu hsecs PL/SQL procedure successfully completed. | 2.Snapshot Too Old 3.可重启的过程需要复杂的逻辑 |
使用自动提交 |
分布式事务
自治事务:允许创建一个事务中的事务,它能独立于其父事务提交或者回滚。