日期:2014-05-16  浏览次数:20282 次

Oracle数据一致性和并发访问

由三种方式读取需要避免:

?


1.脏读取,一个事务读取了其他事务未提交的数据。
2.不可重复读取(nonrepeatable read):一个事务再次读取其之前曾经读取过的数据时,发现数据已被其他已提交的事务修改或删除。
3.不存在读取(phantom read):事务按照之前的条件重新查询时,返回的结果集中包含其他已提交事务插入的满足条件的新数据。


ORACLE强制实现语句级别的读一致性。
ORACLE 在串行化事务隔离级别下能够实现事务级别的读一致性。

?

ORACE支持三种事务隔离级别:
1.已提交读取。ORACLE SELECT语句只能看到语句开始前而不是事务开始前提交的数据。永远不会出现脏读取。
2.串行化? 串行化只能看到事务开始前就已经提交的数据和事务内对数据的修改。可以保证不可重复读取和不存在读取不发生。
3.只读事务。只读事务只能发现事务开始前就已经提交的数据,并且不能执行对数据的修改。


ORACLE默认的级级别是提交读取。这个级别的读取可以避免脏读取。但是不能避免不存在读取与不可重复读取。任一时刻的查询可以得到某一时刻的所有已经提交的值。不管是这个事务提交的还是其他事务提交的。


可以通过执行 alter session set isolation=SERIALIZABLE来使事务隔离级别串行化。
通过执行alter session set isolation='READ COMMITTED'使事务隔离级别为read commit,在ORACLE中,一个很重要的特性就是写不阻塞读。


这样在开发中就存在这样一个问题。如一个预定会议室的程序。如何防止两个同时预定成功。如果有这样一个表。会议室。其中有一个状态列。先查询。如果未预定就更新该列标记成以预定。这样的话就存在这样一种情况。事务a查询(未预定),事务b查询(未预定)。事务a更新(预定),事务b更新(预定)。两个事务都返回预定成功的结果。但是事务a的更新丢失。

这就是丢失更新。有两种解决方法。
第一种;使用select ...* .. for update为该行加锁。使得在事务a加锁后。事务b不能加锁。强制使事务串行化。
第二种,使用update? ...where字句。精确定位行。使查询更新原子化。
我个人更喜欢第二种。因为锁也是资源。第二种更高效一点。