Hibernate悲观锁和乐观锁
Hibernate加锁模式有如下五种,
1、LockMode.NONE,无锁模式
2、LockMode.WRITE ,Hibernate在insert和update的时候会自动使用这种锁
3、LockMode.READ,Hibernate在读取记录的时候会使用这种锁
以上三种锁是Hibernate内部使用的锁
4、LockMode.UPGRADE,这个锁是利用数据库的for update语句来实现,也是悲观锁的实现方式之一
5、LockMode.UPGRADE_NOWAIT,这个锁是针对于Oracle数据库,类似于第四种
悲观锁
所谓的悲观锁,就是在操作事务,总会认为会有其他事务操作同一数据,故不管有没有事务操作,他都对数据加锁。
Hibernate实现悲观锁方式如下:
代码如下:
String hql = "FROM User user where id=1";
Query query = session.createQuery(hql);
query.setLockMode("user", LockMode.UPGRADE);
日志输出如下:
Hibernate: select user0_.id as id0_, user0_.user_name as user2_0_, user0_.password as password0_, user0_.real_name as real4_0_ from test.user user0_ where user0_.id=1 for update
可以看到Hibernate使用了for update。
乐观锁
所谓的乐观锁,就是在操作事务的时候,总会认为就一个事务在操作,故对数据不加锁。
Hibernate实现乐观锁方式两种,
1、版本控制
2、时间戳控制
版本控制
版本控制即是Hibernate在操作数据的时候,会加上对应的version,当然了数据库表中需要有对应的字段,Hibernate会自动维护这个字段
如:
update user set user_name='test' where userId = 1 and version =0
乐观锁解决了不可重复读和第二类更新的问题
例子如下:
首先看配置文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.yindejin.vo.User" table="user" catalog="test">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
</id>
<!-- version必须跟在id后面 -->
<version name="version" type="java.lang.Integer">
<column name="version"></column>
</version>
<property name="userName" type="java.lang.String">
<column name="user_name" length="200" />
</property>
<property name="password" type="java.lang.String">
<column name="password" length="200" />
</property>
<property name="realName" type="java.lang.String">
<column name="real_name" length="200" />
</property>
</class>
</hibernate-mapping>
测试代码如下:
Configuration configuration = new Configuration().configure();
Session session = configuration.buildSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
User user = new User();
user.setUserName("test");
user.setPassword("123456");
session.save(user);
user.setUserName("zhangsan");
transaction.commit();
session.close();
输出的日志如下:
Hibernate: insert into test.user (version, user_name, password, real_name) values (?, ?, ?, ?)
Hibernate: update test.user set version=?, user_name=?, password=?, real_name=? where id=? and version=?
可以看到Hibernate帮助我们自动管理了version。
时间戳控制
时间戳控制类似于version,也是添加一个字段,Hibernate替我们自动管理这个字段。
但是这种方式有一个很大问题,比如使用了F5的应用服务,服务被部署在多台服务器上,Hibernate在获取事件的时候,就会因为各个服务器上的时间不一致导致并发问题,所以并不推荐这种方式。