由于oracle的update、delete等DML语句是单线程的,具有天生的线程安全性。所以我们可以利用DML语句进行大并发环境下数据准确性、一致性控制。

  先来看一下oracle的DML行锁现象,当表中某一条记录正在执行DML操作时,oracle会为该条记录增加行锁,其他线程过来操作时,需等待第一个线程先执行完毕。如下图所示:

java数据库乐观锁的实现 oracle乐观锁sql语句实现_java

第一个会话未提交

java数据库乐观锁的实现 oracle乐观锁sql语句实现_java数据库乐观锁的实现_02

 

第二个会话进入等待状态

java数据库乐观锁的实现 oracle乐观锁sql语句实现_java数据库乐观锁的实现_03

    我们一步步看一下oracle的执行过程

1、当第一个update执行完毕,并提交后,数据库的结果如下:

SQL:

update test2 a set a.status_cd='11',a.version_lock=a.version_lock+1 where a.id=1 and a.version_lock=100;

java数据库乐观锁的实现 oracle乐观锁sql语句实现_java数据库乐观锁的实现_04

 

2、当第二个update执行完毕并提交,数据库的结果如下:

SQL:

update test2 a set a.status_cd='12',a.version_lock=a.version_lock+1 where a.id=1 and a.version_lock=100;

java数据库乐观锁的实现 oracle乐观锁sql语句实现_java数据库乐观锁的实现_05

 

java数据库乐观锁的实现 oracle乐观锁sql语句实现_数据库_06

3、经过第一步和第二步后,数据库中ID=1的记录,状态并不等于12????这就是oracle神奇的地方,也是我们在大并发多终端下,保持数据一致性、准确性的重要依据。

   有了以上的理论依据时,我们在mybatis中实现乐观锁的实现思路如下:

1、在数据库表中增加version字段;

2、数据操作之前,先读取表记录中对应的version值,若是集群环境下,多台服务器可能同时会拿到相同的version,此时你也许会担心,version和id都一致,那会不会重复操作某条记录啊?不用担心,继续往下看....

3、当多个线程同时更新某一条记录时,oracle的行锁机制,同时只会让某一个线程来操作这条记录,操作成功后version+1,那么其他线程所持有的version已经是旧的了,当执行update操作时,无法找到对应的记录进行操作;

4、我们可以在程序后根据update执行的结果所对应的行数rows,来判断是否为0,如果是,则说明该条记录已被其他线程操作过了,程序无需进去往下执行,直接跳出即可;

5、以上过程可以封装为mybatis的插件,让插件自动在需要的sql中追加version版本控制;