事务管理
乐观锁和悲观锁
为什么需要锁?
在多用户环境中,在同一时间会有多个用户更新相同的记录,这会产生冲突。这就是著名的并发性问题。
典型的冲突有:
1. 丢失更新:一个事务的更新覆盖了其他事务的更新效果,就是所谓的更新丢失。例如:用户A把值从6改为2,用户B把2改为6,则用户A丢失了他的更新。
2. 脏读:当一个事务读取它完成一半的事务的记录时,就会发生脏读。例如用户A,B看到的值都是6,用户B把值改为2,用户A读到的值仍为6。
为了解决这些并发带来的问题。我们需要引入并发控制机制
并发控制机制
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。
乐观锁:假定不会发生并发冲突,只是在提交操作时检查是否违法数据完整性。乐观锁不能解决脏读的问题。
悲观锁实现方式
JDBC:在JDBC中使用悲观锁,需要使用select for update语句,假如我们系统中有一个Account的类,我们可以采用如下的方式进行:
select * from Account where … ( where condition) for update.
当使用了for update语句后,每次在读取或加载一条记录的时候,都会锁住被加载的记录,那么当其它事务如果要更新或者加载此条记录就会因为不能获得锁而阻塞,这样就避免了不可重复读以及脏读的问题,但是其他事务还是可以插入和删除记录,这样也许同一事务中的两次读取会得到不同的结果集,但是这不是悲观锁造成的问题,这是我们数据库隔离级别所造成的问题。
最后还需要注意的一点就是每个冲突的事务中,我们必须使用select for update语句来进行数据库的访问,如果一些事务没有使用select for update语句,那么久会很同一造成错误,这也是采用JDBC进行悲观控制的缺点。
乐观锁
乐观锁是在同一数据库事务中我们常采取的策略,因为它能使得我们的系统保持高的性能的情况下提高很好的并发访问。
实现方式:
大多是基本数据版本(Version)记录机制实现。何为数据版本?即为数据增加了一个版本标志,在基于数据库表的版本解决方案中,一般是通过为数据库增加一个version字段来实现。
读取数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库对应记录的当前版本信息进行比对,如果提交的数据版本大于数据库表当前版本号,则予以更新,否则认为是过期数据。
在实际生产环境中,如果并发量不大且不允许脏读,可以使用悲观锁解决并发问题,但如果系统的并发非常大的话,悲观锁会带来非常大的性能问题,所以我们就要选择乐观锁定的方法。
浙公网安备 33010602011771号