由于oracle的update、delete等DML语句是单线程的,具有天生的线程安全性。所以我们可以利用DML语句进行大并发环境下数据准确性、一致性控制。
先来看一下oracle的DML行锁现象,当表中某一条记录正在执行DML操作时,oracle会为该条记录增加行锁,其他线程过来操作时,需等待第一个线程先执行完毕。如下图所示:
第一个会话未提交
第二个会话进入等待状态
我们一步步看一下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;
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;
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版本控制;