在Oracle关系数据库中,我们先来看下面这个问题:
A事务:select <cols> from T where id > 10 and id < 10000;
B事务:update T set id = 45000 where id = 4501
两个事务按下面的顺序执行:
A事务:|--------------------------------|commit
B事务: |-------------|commit
也就是A事务先开始执行,过一段时间B事务再开始执行,但是B事务先执行完并commit提交了,A事务又过了一段时间才完成。那么问题来了,在这种情况下,问A事务能不能取得正确的结果,两个事务之间会不会有干扰,怎么干扰?
这是一个典型的关系型数据库事务的隔离性问题,而且,针对不同的数据库(存储引擎),可能会有不同的表现。
在执行DML语句时,Oracle会给每一行增加一个sn序列号,比如select <cols> from T where id > 10 and id < 10000;这条语句,查询出将近1w条数据,在执行扫描的时候,发现符合条件的行就会加一个sn(实际操作时,可能是和内存中某个sn数值关联起来),这个sn序列号实际上被当做乐观锁使用。
那么可能出现下面的情况,事务A的select语句还没有执行完,当执行到2000条的时候,B开始了一个update T set id = 45000 where id = 4501的事务,由于在oracle中,写锁的级别高于读锁,因此这时候B事务的update语句取得写锁,成功执行完并commit,交出写锁。
当先开始的select语句执行到4501时,如果此时B事务已经commit,那么A事务会接着执行下去,成功commit,反之,当A事务执行到4501行时,B事务还未commit,那么二者的锁在4501这条数据发生冲突,这时整个A事务就会出错。