问题描述
一个典型的倚赖数据库的悲观锁调用:select*fromaccountwherename=”Erica”forupdate这条sql语句锁定了account表中所有符合检索条件(name=”Erica”)的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。Hibernate的悲观锁,也是基于数据库的锁机制实现。下面的代码实现了对查询记录的加锁:StringhqlStr="fromTUserasuserwhereuser.name='Erica'";Queryquery=session.createQuery(hqlStr);query.setLockMode("user",LockMode.UPGRADE);//加锁ListuserList=query.list();//执行查询,获取数据query.setLockMode对查询语句中,特定别名所对应的记录进行加锁(我们为TUser类指定了一个别名“user”),这里也就是对返回的所有user记录进行加锁。观察运行期Hibernate生成的SQL语句:selecttuser0_.idasid,tuser0_.nameasname,tuser0_.group_idasgroup_id,tuser0_.user_typeasuser_type,tuser0_.sexassexfromt_usertuser0_where(tuser0_.name='Erica')forupdate这里Hibernate通过使用数据库的forupdate子句实现了悲观锁机制。Hibernate的加锁模式有:ØLockMode.NONE:无锁机制。ØLockMode.WRITE:Hibernate在Insert和Update记录的时候会自动获取。ØLockMode.READ:Hibernate在读取记录的时候会自动获取。以上这三种锁机制一般由Hibernate内部使用,如Hibernate为了保证Update过程中对象不会被外界修改,会在save方法实现中自动为目标对象加上WRITE锁。ØLockMode.UPGRADE:利用数据库的forupdate子句加锁。ØLockMode.UPGRADE_NOWAIT:Oracle的特定实现,利用Oracle的forupdatenowait子句实现加锁。上面这两种锁机制是我们在应用层较为常用的,加锁一般通过以下方法实现:Criteria.setLockModeQuery.setLockModeSession.lock注意,只有在查询开始之前(也就是Hiberate生成SQL之前)设定加锁,才会真正通过数据库的锁机制进行加锁处理,否则,数据已经通过不包含forupdate子句的SelectSQL加载进来,所谓数据库加锁也就无从谈起。