ORA-08177: 无法连续访问此事务处理 (转载)
原文地址:http://blog.csdn.net/wyzxg/archive/2009/11/20/4842769.aspx
author:skate
time:2009-11-20
今天在消息的接受日志中,发现一个错误.ORA-08177: 无法连续访问此事务处理.
觉得有点束手无策,于是停下许多工作,开始解决此错误.
首先怀疑,错误就是并发造成.根据日志显示,同一秒内,处理了7,8笔数据.所以就先从这里下手.
后根据ORA-08177在网上查处错误解释.
Cannot serialize access 不能序列访问.说是Oracle中比较郁闷的 错误.
后来找到一个重现的例子.如下:
这个问题是由oracle 事务隔离级别引起的
在一个事务中执行
update t set object_type='zl' where object_id=17286
不要 提交此事务
然后再其他事务中执行
set transaction isolation level serializable;
update t set object_type='zl' where object_id=17286
这个时候事务2 会等待事务1执行完成,提交事务1 的时候会出现上述问题
我把SQL改成操作的对应消息的表,发现的确如此.但是其中最重要的一句话是set transaction isolation level serializable;就是将这个事务,序列化,如下所述:
隔离级别(isoation eve)
隔离级别定义了事务与事务之间的隔离程度。
隔离级别与并发性是互为矛盾的:隔离程度越高,数据库的并发性越差;隔离程度越低,数据库的并发性越好。
ANSI/ISO SQ92标准定义了一些数据库操作的隔离级别:
- 未提交读(read uncommitted)
- 提交读(read committed)
- 重复读(repeatabe read)
- 序列化(seriaizabe)
通过一些现象,可以反映出隔离级别的效果。这些现象有:
- 更新丢失(ost update):当系统允许两个事务同时更新同一数据是,发生更新丢失。
- 脏读(dirty read):当一个事务读取另一个事务尚未提交的修改时,产生脏读。
- 非 重复读(nonrepeatabe read):同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。(A transaction rereads data it has previousy read and finds that another committed transaction has modified or deeted the data. )
- 幻 像(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻像读。(A transaction reexecutes a query returning a set of rows that satisfies a search condition and finds that another committed transaction has inserted additiona rows that satisfy the condition. )
下面是隔离级别及其对应的可能出现或不可能出现的现象
Dirty Read | NonRepeatabe Read | Phantom Read | |
Read uncommitted | Possible | Possible | Possible |
Read committed | not possible | Possible | Possible |
Repeatabe read | not possible | not possible | Possible |
Seriaizabe | not possible | not possible | not possible |
ORACE的隔离级别
ORACE提供了SQ92标准中的read committed和seriaizabe,同时提供了非SQ92标准的read-ony。
read committed:
- 这是ORACE缺省的事务隔离级别。
- 事务中的每一条语句都遵从语句级的读一致性。
- 保证不会脏读;但可能出现非重复读和幻像。
seriaizabe:(串行执行事务,并发性最小)
- 简单地说,seriaizabe就是使事务看起来象是一个接着一个地顺序地执行。
- 仅仅能看见在本事务开始前由其它事务提交的更改和在本事务中所做的更改。
- 保证不会出现非重复读和幻像。
- Seriaizabe隔离级别提供了read-ony事务所提供的读一致性(事务级的读一致性),同时又允许DM操作。
如果有在seriaizabe事务开始时未提交的事务在seriaizabe事务结束之前修改了seriaizabe事务将要修改的行并进行了提交,则seriaizabe事务不会读到这些变更,因此发生无法序列化访问的错误。(换一种解释方法:只要在seriaizabe事务开始到结束之间有其他事务对seriaizabe事务要修改的东西进行了修改并提交了修改,则发生无法序列化访问的错误。)
ORACE在数据块中记录最近对数据行执行修改操作的N个事务的信息,目的是确定本事务开始时,是否存在未提交的事务修改了本事务将要修改的行。
read-ony:
- 遵从事务级的读一致性,仅仅能看见在本事务开始前由其它事务提交的更改。
- 不允许在本事务中进行DM操作。
- read ony是seriaizabe的子集。它们都避免了非重复读和幻像。区别是在read ony中是只读;而在seriaizabe中可以进行DM操作。
- Export with CONSISTENT = Y sets the transaction to read-ony.
read committed和seriaizabe的区别和联系:
事务1先于事务2开始,并保持未提交状态。事务2想要修改正被事务1修改的行。事务2等待。如果事务1回滚,则事务2(不论是read committed还是seriaizabe方式)进行它想要做的修改。如果事务1提交,则当事务2是read committed方式时,进行它想要做的修改;当事务2是seriaizabe方式时,失败并报错“Cannot seriaize access”,因为事务2看不见事务1提交的修改,且事务2想在事务1修改的基础上再做修改。
即seriaizabe不允许存在事务嵌套
read committed和seriaizabe可以在ORACE并行服务器中使用。
关于SET TRANSACTION READ WRITE:read write和read committed 应该是一样的。在读方面,它们都避免了脏读,但都无法实现重复读。虽然没有文档说明read write在写方面与read committed一致,但显然它在写的时候会加排他锁以避免更新丢失。在加锁的过程中,如果遇到待锁定资源无法锁定,应该是等待而不是放弃。这与 read committed一致。
语句级的读一致性
- ORACE保证语句级的读一致性,即一个语句所处理的数据集是在单一时间点上的数据集,这个时间点是这个语句开始的时间。
- 一个语句看不见在它开始执行后提交的修改。
- 对于DM语句,它看不见由自己所做的修改,即DM语句看见的是它本身开始执行以前存在的数据。
事务级的读一致性
- 事务级的读一致性保证了可重复读,并保证不会出现幻像。
设置隔离级别
设置一个事务的隔离级别
- SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
- SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
- SET TRANSACTION READ ONLY;
设置增个会话的隔离级别
- ATER SESSION SET ISOLATION_LEVE SERIALIZABLE;
- ATER SESSION SET ISOLATION_LEVE READ COMMITTED;
Choice of Isolation Level
Read Committed Isolation
两种情况:(1)在事务量大、高性能的计算环境,需要更高的吞吐量和响应时间;(2)事务数少,并且发生幻影和不可重复读的几率的比较低
Serializable Isolation
(1)适合于很少存在两个事务同时修改同一条记录的情况
(2)长事务以只读为主
(3)大型数据库并且每个短事务只修改很少的记录
如此我就在消息的接口中,找到运行SQL的公用方法,发现执行批量SQL的方法,这里将执行事务的级别设置为了Serializable(序列化),就此就真相大白了,剩下的就是商讨如何解决了.
-----end------