4,事务处理
Oracle是基于事务的,oracle以用户事务来确保数据的完整性。一个事务就是将一系列的数据操纵的sql语句作为一个逻辑单元,逻辑单元里面的单个操作要么全做,要么全部不做,以保证数据的完整性。
事务结束时将产生数据库的更改,oracle使用undo来记录所有的更改,如果程序在事务未完成之前发生了错误,oracle将会检测到这个错误,并回滚当前的事务,撤销从事务开始时的更改。保存点(savepoint)标记了当前事务处理的一个状态点,结合使用rollback,savepoint可以撤销部分事务,使用set transaction可以设置事务的属性,比如读写访问和隔离级别。
事务隔离级别
SQL92定义了四种事务隔离级别(transaction isolation level),主要是为了在并发事务执行时阻止下列现象发生:
脏读:事务读取了被其他事务写入但未提交的数据。
不可重复读:一个事务再次读取其之前曾经读取过的数据时,发现数据已被其他已提交的事务修改或删除。
幻象读(phantom read):事务按照之前的条件重新查询时,返回的结果集中包含其他已提交事务插入的满足条件的新数据。
提供的四种隔离级别分别不同程度的对这三种现象做了限制:
隔离级别 | 脏读 | 不可重复读 | 幻象读 |
未提交读取 (read uncommitted) | 允许 | 允许 | 允许 |
已提交读取 (read committed) | 不允许 | 允许 | 允许 |
可重复读取 (repeatable read) | 不允许 | 不允许 | 允许 |
串行化 (serializable) | 不允许 | 不允许 | 不允许 |
Oracle支持三种事务隔离级别,分别是
已提交读取,串行化,只读(read only),默认的事务隔离级别是已提交读取。
Oracle事务隔离级别 | 脏读 | 不可重复读 | 幻象读 | 事务内使用 DML操作数据 |
Read committed 已提交读取 | 不允许 | 允许 | 允许 | 允许 |
Serializable 串行化 | 不允许 | 不允许 | 不允许 | 允许 |
Read only 只读 | 不允许 | 不允许 | 不允许 | 不允许 |
Oracle允许在事务开始时使用语句来设定事务的级别,以下三个语句分别设定oracle的三种事务隔离级别:
set transaction isolation level read committed;
set transaction isolation level serializable;
set transaction read only;
Plsql事务处理的语句有下列一些:
Commit, rollback, savepoint, rollback to savepoint, set transaction ,lock table等。
例如:
Set transaction read only
这个语句建立一个事务级的读一致性,事务内所有的查询所见的都是事务开始之前的改变,只读事务对于表有修改的许多查询报表来说比较有用。这个语句不适用于SYS用户,意味着,即使SYS用户设置事务为只读,查询也会返回事务期间的更改。
测试:
Scott用户下:
Session1:
SQL> set transaction read only;
Transaction set
SQL> select sum(sal) from scott.emp ;
SUM(SAL)
----------
28124.2
Session2:
SQL> update scott.emp a set a.sal = a.sal + 1.1;
14 rows updated
SQL> commit;
Commit complete
Session1:
SQL> select sum(sal) from scott.emp ;
SUM(SAL)
----------
28124.2
SQL> commit;
Commit complete
SQL> select sum(sal) from scott.emp ;
SUM(SAL)
----------
28139.6
很容易看出set transaction read only的效果,如果实在sys下面,情况则是这样的:
Session1:
SQL> set transaction read only;
Transaction set
SQL> select sum(sal) from scott.emp ;
SUM(SAL)
----------
28139.6
Session2:
SQL> update scott.emp a set a.sal = a.sal + 1.1;
14 rows updated
SQL> commit;
Commit complete
SQL>
Session1:
SQL> select sum(sal) from scott.emp ;
SUM(SAL)
----------
28155
在plsql中使用set transaction read only需要在事务开始之前提交或者回滚,结束后也一般需要提交或者回滚例如:
declare
v_sum_sal scott.emp.sal%type;
begin
rollback work;
set transaction read only;
select sum(sal) into v_sum_sal from scott.emp;
dbms_output.put_line(v_sum_sal);
commit;
end;
/
事实上,这是由于使用set transaction read only以后,就会有一个事务产生:
SQL> set transaction read only;
Transaction set
SQL> select a.XIDUSN, a.UBAREC, a.UBABLK, a.USED_UBLK, a.USED_UREC from v$transaction a;
XIDUSN UBAREC UBABLK USED_UBLK USED_UREC
---------- ---------- ---------- ---------- ----------
2 0 0 1 1
SQL> commit;
Commit complete
SQL> select a.XIDUSN, a.UBAREC, a.UBABLK, a.USED_UBLK, a.USED_UREC from v$transaction a;
XIDUSN UBAREC UBABLK USED_UBLK USED_UREC
---------- ---------- ---------- ---------- ----------
Set transaction read write
再来看看:
Savepoint ,rollback to savepoint,commit
下面这段代码很容易看出这几个语句的使用方式和效果
SQL> set serveroutput on;
declare
v_sal scott.emp.sal%type;
begin
savepoint sp_1;
update scott.emp a set a.sal = a.sal + 1 where a.empno = 7369;
select sal into v_sal from scott.emp a where a.empno = 7369;
dbms_output.put_line(v_sal);
savepoint sp_2;
update scott.emp a set a.sal = a.sal + 1 where a.empno = 7369;
rollback to sp_2;
commit;
select sal into v_sal from scott.emp a where a.empno = 7369;
dbms_output.put_line(v_sal);
end;
16 /
810.6
810.6
PL/SQL procedure successfully completed
再看看lock table的几种方式:
Lock table in
ROW SHARE
ROW EXCLUSIVE
SHARE UPDATE
SHARE
SHARE ROW EXCLUSIVE
EXCLUSIVE
[nowait]
可以简单看看各种类型锁定的情况,结合nowait参数来看看lmode和ctime的变化。
示例share mode和row exclusive mode:
SQL> lock table scott.emp in share mode nowait;
Table(s) locked
SQL> select sid from v$mystat a where rownum = 1;
SID
----------
150
SQL> select * from v$lock a where a.SID = 150;
ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK
-------- -------- ---------- ---- ---------- ---------- ---------- ---------- ---------- ----------
41DC66F4 41DC670C 150 TM 51564 0 4 0 45 0
41E10938 41E1095C 150 TX 458775 3256 6 0 45 0
SQL> rollback;
Rollback complete
SQL> lock table scott.emp in row exclusive mode nowait;
Table(s) locked
SQL> select * from v$lock a where a.SID = 150;
ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK
-------- -------- ---------- ---- ---------- ---------- ---------- ---------- ---------- ----------
41DC66F4 41DC670C 150 TM 51564 0 3 0 6 0
41E10938 41E1095C 150 TX 65558 3276 6 0 6 0
SQL> commit;
Commit complete