Oracle 事务的特征
ACID,指数据库事务正确执行的四个基本要素的缩写.包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持交易(Transaction)的数据库系统,必需要具有这四种特性,否则在交易过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求.
原子性 (ATOMICITY)
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性 (CONSISTENCY)
在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
隔离性 (ISOLATION)
两个事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。
持久性 (DURABILITY)
在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
oracle中通常情况下有三种读:
第一种:错读(未提交读),就是读到另一个事物修改过的但没有提交的数据,没有实一致性读。
第二种:不可重复读( 读失真)就是对一个事物前后两次读,读出来的值是不相等的,因为它在这两次读的间隔被别的事物修改或者删除,并且提交了。
第三种读:幻想读 某个事务在两次读之间,有另一事务插入新的数据,并提交,而且插入的数据满足查询的条件,导致读到的数据不一样。
oracle读一致性又分为:
1.语句级读一致性(不可重复读)
2.事务级一致性读
语句性一致性读,比如语句在开始执行之前获得当前的scn号为10001,而另个事务T2可能将该块的行进行修改,设置该行所在块的一致性标记,生成的SCN=10002,这种情况就需要应用undo回滚到scn为10001的时刻,即为一致性状态,在单个语句执行期间这个值是不会改变的。
事务级别一致性读,所有数据的状态是在事务起始的状态,除非本事务修改的数据,这样就可以避免了不可重复读和幻想读。
oracle是通过隔离级来实现事务的一致性读,事务级可以通过回滚段能实现一致性读,虽然别人可能修改了,但是可以利用回滚段,把别人修改的给回滚了。
事务级一致性读就得说道串行读所谓串行读就是你一人在读的话,别人修改不影响你读的结果,可以无视别人的修改。虽然对于数据库是生效了,但是对于串行事务,则被无视。
串行读适合用在下面三种情况:
a.大型数据库中大多是小数据集的DML短事务
b.修改同一行的几率非常低的系统.
c.长运行事务主要是只读的系统
这块主要是从回滚段来考虑的,应为串行读是通过回滚段来实现的。
设置隔离级命令
代码如下 | 复制代码 |
1.SET TRANSACTION ISOLATION LEVEL READ COMMITTED;(提交度隔离级) |
还有一种设置
代码如下 | 复制代码 |
ALTER SESSION |
下面来举一个串行隔离的例子,代码如下
代码如下 | 复制代码 |
SQL> create table t ( x int ); Table created SQL> insert into t values ( 1 ); 1 row inserted SQL> commit; Commit complete SQL> set transaction isolation level serializable; Transaction set SQL> select * from t; X --------------------------------------- 1 SQL> SQL> declare 2 pragma autonomous_transaction; 3 begin 4 delete from t; 5 commit; 6 end; 7 / PL/SQL procedure successfully completed SQL> select * from t; X --------------------------------------- 1 SQL> commit; Commit complete SQL> select * from t; X |
---------------------------------------
中间用到的是自制事务,相当于重新启动了一个事务,通过例子可以看出,虽然删除了,但是第一个事务仍然可以看到,这块其实在数据库中已经修改了,只是通过回滚段可以看到,最后一提交,再查看,就会发现真正的删除了。
我们开始试验一,模拟语句级别读一致性。第一个session使用显示打开一个游标模拟数据读,同时在游标读数据的过程中,启动另外一个session更改数据,我可以看到另外一个session对数据的更改,并不会改变到第一个session的读。这就是语句级别的读一致性。
启动一个session连接数据库:
代码如下 | 复制代码 |
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 Connected as cbo SQL> set serveroutput on; SQL> SQL> create table test(id number,name varchar2(10)); Table created SQL> insert into test values(1,'a'); 1 row inserted SQL> insert into test values(2,'b'); 1 row inserted SQL> commit; Commit complete SQL> SQL> declare 2 cursor cur is select * from test; 3 begin 4 for rec in cur 5 loop 6 dbms_output.put_line(rec.name); 7 dbms_lock.sleep(10);--中间等待另外一个session启动并执行更新数据操作 8 end loop; 9 end; 10 / a b PL/SQL procedure successfully completed SQL> |
在执行游标打印输出的时候同时启动另外一个进程,执行更新数据操作:
代码如下 | 复制代码 |
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.1.0
|
下面我们开始试验二,模拟事务级别读一致性。
首先启动一个SESSION,读一次数据:
代码如下 | 复制代码 |
SQL> SET TRANSACTION READ ONLY;
|
接下来我们启动另外一个session,执行更新数据操作:
代码如下 | 复制代码 |
SQL> update test set name='123456'; |
最后我们回到第一session查看再次查看数据:
代码如下 | 复制代码 |
SQL> select * from test; |
我们会发现读出的数据并没有发生改变。所以在设置了SET TRANSACTION READ ONLY后,一个事务前后语句读取的数据不会因为其他seesion对数据的更新而改变。
Oracle事务管理
一个事务包含一个或多个SQL语句,是逻辑管理的工作单元(原子单元)。
一个事务开始于第一次执行的SQL语句,结束于Commit 或 Rollback 或 DDL语句。
注意:其中Commit, Rollback是显示的提交事务,而DDL语句是隐式的提交事务的。DDL语句的操作是
没有办法回滚的。
##########################
代码如下 | 复制代码 |
eg: 表已创建。 SQL> insert into a values(1); 已创建 1 行。 SQL> create table b ( i int); 表已创建。 SQL> rollback; 回退已完成。 SQL> select * from a; I |
#############################
在执行create table b 的时候事务就已经提交了。
事务结束的地方有:
1>. 执行Commit, Rollback, 没有使用savepoint.
2>. 执行DDL操作如:create , drop, rename, alter
3>. 断开与Oracle的连接,事务将自动提交。
4>. 用户进程异常终止,当前事务回滚。
注意:应用程序与Oracle连接的情况,在应用程序终止前必须显示的提交(Commit)或回滚(Rollback)。
Commit操作Oracle做了:
1>. 与UNDO表空间关联的内部事务表记录该事务已经提交,产生唯一的系统交易号(SCN)保存到该表
中。
2>. LGWR进程将SGA中的重做日志写入redo log文件,当然也要写SCN到重做日志文件。
3>. Oracle释放锁定表中的行。
4>. Oracle设置该事务完成。
注意:Commit操作前的改变数据(保存在SGA)不会马上写到数据文件中。这样做的目的也是为了数据
库更高效。从开发人员的角度想想也是这样的,这样可以减少很多小事务的多次写磁盘的。
Oracle 10.2中与事务有关的:
代码如下 | 复制代码 |
commit work write immediate wait; --是Oracle默认的设置。 alter system set commit_write = nowait; --改变系统提交方式 alter session set commit_write = nowait; --改变会话提交方式 |
##############################
提交一个事务 eg:
代码如下 | 复制代码 |
SQL> commit work; |
提交完成。
代码如下 | 复制代码 |
SQL> show autocommit; |
表已创建。
代码如下 | 复制代码 |
SQL> insert into t0 values(1); |
已创建 1 行。
SQL> commit;
提交完成。
代码如下 | 复制代码 |
SQL> select * from t0; TESTCOL SQL> insert into t0 values(2); 已创建 1 行。 SQL> commit work; |
提交完成。
代码如下 | 复制代码 |
SQL> select * from t0; TESTCOL #################################### |