`
topcat
  • 浏览: 282486 次
  • 性别: Icon_minigender_1
  • 来自: 湖北武汉
社区版块
存档分类
最新评论

oracle数据库并发三

阅读更多

多版本模型与一致性读

一致性读

select 查询接触到一个被X 锁的块时,Oracle 绕开锁,并从回滚段中重构数据; 以实现数据的一致读。

Oracle 自动在查询上提供读一致性以使查询所能看到的数据均来自一个时间点上。

同样,ORACLE 也提供事务中所有查询的一致性,如你的update 就是一个事务。

Oracle 为保证一致性用回滚段来保存未提交或最近已提交的数据的旧值。

当查询进行的时候. 当前SCN 已被决定,因此, 每个查询返回所有截止于在查询执行点上的那个SCN 的所有提交的数据,在查询期间发生的其他事务改变不会被用到。

因此如果在查询前提交该事务. 那么数据是可见的。

读取操作只会读取读取查询开始时那一时刻的数据,如果数据在读取操作以后发生了变化,则从回滚段中读取old image

例子

假设表Acol1 的值初始为9

时间点

Session1

Session2

T1

开始事务

 

T2

 

Select col1 from A where id=1

( 值为9)

T3

Update A set col1=2 where id=1

 

T4

 

Select col1 from A where id=1

( 值为9)

T5

commit

 

T6

 

Select col1 from A where id=1

( 值为2)

假设查询开始时间为 T1 ,则在查询获取的数据块中,如果数据块的提交 SCN 小于 T1 ,则 oracle 接收该数据,如果提交 SCN 大于 T1 或数据被锁定修改尚未记录 commit SCN ,则 oracle 需要通过回滚段构造前镜像来返回结果,这就是一致性读的本质含义。

当前读

       为了提高事务处理的速度, oracle 采用了读一致性机制。就是当一个会话更新数据后未提交时,其它会话读取到更新前的结果。这大大提高数据并发的效率,但某些特定条件下会产生错误的结果。

下面的例子进行说明。

假设存在表 test A number(10,2) )其中有一行记录,字段 A 的值为 100

test

A

100

 

时间点

Session1

Session2

T1

update test set A=(select A+1 from test)

 

T2

commit

 

T3

 

update test set A=(select A+1 from test)

T4

 

commit

当会话 1 提交后再执行会话 2 时,得到得结果是 102

时间点

Session1

Session2

T1

update test set A=(select A+1 from test)

 

T2

 

update test set A=(select A+1 from test)

T3

commit

 

T4

 

commit

 

当会话 1 执行后未提交,会话 2 就已经执行,得到得结果是 101 ,并不是 102 。这是因为 oracle 为了提供数据的并发访问速度,在一个会话更新数据后未提交时,另一个会话 select 到的将是第一个会话更新前的数据

单多个会话并发时,会产生不确定得结果,这不是我们想看到的。在并发系统开发时应多注意此类问题。

上面的两个会话可以改成以下做法,保证数据的准确更新

时间点

Session1

Session2

T1

update test set A=A+1

 

T2

 

update test set A=A+1

T3

commit

 

T4

 

commit

Oracle 的当前读会使 session2 看到 session1 做出的修改

 

更新丢失

例子

时间点

Session1

Session2

T1

开始事务

 

T2

 

开始事务

T3

Update auction set status=’ 卖出 ’ where auction_id=1

 

T4

 

Update auction set status=’ 卖出 ’ where auction_id=1

T5

commit

 

T6

 

commit

上例中,如果在业务逻辑上是在拍卖一个商品,那么同时这一个商品会被 session1 的用户与 session2 的用户同时拍到。

采用悲观锁或乐观锁可保证同一商品不会被两人同时拍到

悲观锁

时间点

Session1

Session2

T1

开始事务

 

T2

 

开始事务

T3

Select * from auction where auction_id=1 for update nowait

 

T4

Update auction set status=’ 卖出 ’ where auction_id=1

 

T5

 

Select * from auction where auction_id=1 for update nowait

T6

 

Update auction set status=’ 卖出 ’ where auction_id=1

T7

commit

 

T8

 

commit

Session2 T5 时刻发现有人锁定了要修改的行,则无法锁定成功, update 操作将不会执行

 

乐观锁

时间点

Session1

Session2

T1

开始事务

 

T2

 

开始事务

T3

Update auction set status=’ 卖出 ’ where auction_id=1 and status=’ 未卖出

 

T4

 

Update auction set status=’ 卖出 ’ where auction_id=1 and status=’ 未卖出

T5

commit

 

T6

 

commit

Session2 T4 时刻由于当前读, status=’ 未卖出 的行已读不到,所以 session2 的用户没有更新到行。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics