Hibernate锁机制
在Hibernate项目中,如果不同的Session读取了同一个数据,并同时对此数据发出更新操作,所以为了保证数据可以正常的同步进行操作,就需要锁这一概念完成。
在Hibernate中提供有两种锁的机制:
- 悲观锁(Optimistic):指的是使用数据库中的概念来进行数据的锁定
- 乐观锁(Pessimistic):利用程序的逻辑来实现锁的处理
悲观锁
悲观锁主要依靠数据库的支持来完成,它是在SQL上的处理。悲观锁的操作通过程序编码实现,在查询接口(Query、Criteria)里有如下方法:
方法 | 描述 |
---|---|
public Query setLockMode(String alias,LockMode lockMode) | 设置锁定 |
public Criteria setLockMode(LockMode lockMode) | 设置锁定 |
alias表示在使用此方法·接口锁定数据时使用的别名(HQL中定义的查询别名),而对于锁定,有以下几种模式:
模式名 | 解释 |
---|---|
public static final LockMode READ | 读取时锁定 |
public static final LockMode WRITE | 写入时锁定 |
public static final LockMode UPGRADE_NOWAIT | 不等待锁定 |
【观察锁定操作】
import com.gub.dbc.HibernateSessionFactory;
import com.gub.vo.Dept;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class QueryLock {
public static void main(String[] args) {
String hql = "FROM Dept AS d WHERE d.deptno=?";
SessionFactory sessionFactory = HibernateSessionFactory.getSessionFactory();
Session session = sessionFactory.openSession();
Query query = session.createQuery(hql);
query.setLockMode("d",LockMode.UPGRADE_NOWAIT);
query.setParameter(0,1);
Dept dept = (Dept)query.uniqueResult();
}
}
观察结果
Hibernate: select dept0_.deptno as deptno1_0_, dept0_.address as address2_0_, dept0_.credate as credate3_0_, dept0_.dname as dname4_0_, dept0_.tel as tel5_0_ from Dept dept0_ where dept0_.deptno=? for update
观察结果发现,在当前Session操作之中,数据将采取锁定的模式,而其他的Session将无法进行直接更新,如果出现了不能更新的情况,也不会进行等待。
乐观锁
乐观锁不通过数据库进行同步的锁处理,而是将所有的操作都交给程序来实现,乐观锁采用的是一种逻辑模式的处理方式,如果想要使用乐观锁,那么就必须进行表结构的修改,也就是说除了可以正常使用的数据字段之外,在乐观锁的操作过程之中还需要准备出一个用于进行锁定逻辑判断的字段,这个字段可以是int或者date。
乐观锁的操作流程:
【观察乐观锁操作】
- 创建数据表
CREATE TABLE Person(
id int primary key,
name varchar(50),
tel varchar(50),
version int
);
INSERT INTO Person (id,name,tel,version) VALUES (1,"姓名-1","0471-4511566",1);
- 修改Person.hbm.xml文件
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.gub.vo.Person" table="person" schema="company">
<id name="id" column="id"/>
<!--version字段作为乐观锁判断的逻辑列-->
<version name="version" column="version" type="int" />
<property name="name" column="name"/>
<property name="tel" column="tel"/>
</class>
</hibernate-mapping>
- 编写测试程序
import com.gub.dbc.HibernateSessionFactory;
import com.gub.vo.Person;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class PessimisticTest {
public static void main(String[] args) {
SessionFactory sessionFactory = HibernateSessionFactory.getSessionFactory();
Session sessionA = sessionFactory.openSession();
Session sessionB = sessionFactory.openSession();
Person personA = (Person)sessionA.get(Person.class,1);
Person personB = (Person)sessionB.get(Person.class,1);
System.out.println("personA="+personA);
System.out.println("personB="+personB);
personA.setName("没名字");
sessionA.update(personA);
sessionA.beginTransaction().commit();
personB.setName("SessionB");
sessionB.update(personB);
sessionB.beginTransaction().commit();
}
}
运行程序后发现由于乐观锁的存在,SessionB并不能进行修改操作:
如果项目是基于Annotation开发的,那么对于乐观锁的配置只需要在逻辑列加上Version注解即可