ORA-08177: can't serialize access for this transaction
看一下这个报错:
ORA-08177: can't serialize access for this transaction
从字面上来看:无法串行访问事务错误
当事务隔离级别为serializable,两个事务并发修改同一个对象,当前一个事务提交或回滚时,第二个事务会收到该错误。
查看数据库Oracle的隔离级别:
1. SELECT * FROM dual FOR UPDATE;
2. SELECT s.sid, s.serial#,
CASE BITAND(t.flag, POWER(2, 28))
WHEN 0 THEN 'READ COMMITTED'
ELSE 'SERIALIZABLE'
END AS isolation_level
FROM v$transaction t
JOIN v$session s ON t.addr = s.taddr AND s.sid = sys_context('USERENV', 'SID');
2.在一个事物中执行修改的语句
update ds_batch_file_record dd set dd.status='S' where dd.table_name='PC.FGNT';
这个时候不要提交
3.在另外一个事物中执行
set transaction isolation level serializable;
update ds_batch_file_record dd set dd.status='T' where dd.table_name='PC.FGNT';
4.将第一个事物提交
5.第二个事物中就出现了报错:
我们回顾一下Oracle的事物的隔离级别:
ORACE提供了SQ92标准中的read committed和seriaizabe,同时提供了非SQ92标准的read-ony。
1.这是ORACE缺省的事务隔离级别。
2.事务中的每一条语句都遵从语句级的读一致性。
3.保证不会脏读;但可能出现非重复读和幻像。
串行化(seriaizabe)
1.简单地说,seriaizabe就是使事务看起来象是一个接着一个地顺序地执行。
2.仅仅能看见在本事务开始前由其它事务提交的更改和在本事务中所做的更改。
3.保证不会出现非重复读和幻像。
4.Seriaizabe隔离级别提供了read-ony事务所提供的读一致性(事务级的读一致性),同时又允许DM操作。
如果有在seriaizabe事务开始时未提交的事务在seriaizabe事务结束之前修改了seriaizabe事务将要修改的行并进行了提交,则seriaizabe事务不会读到这些变更,因此发生无法序列化访问的错误。(换一种解释方法:只要在seriaizabe事务开始到结束之间有其他事务对seriaizabe事务要修改的东西进行了修改并提交了修改,则发生无法序列化访问的错误。)
ORACE在数据块中记录最近对数据行执行修改操作的N个事务的信息,目的是确定本事务开始时,是否存在未提交的事务修改了本事务将要修改的行。
1.遵从事务级的读一致性,仅仅能看见在本事务开始前由其它事务提交的更改。
2.不允许在本事务中进行DM操作。
3.read ony是seriaizabe的子集。它们都避免了非重复读和幻像。区别是在read ony中是只读;而在seriaizabe中可以进行DM操作。
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修改的基础上再做修改。