Hibernate 悲观锁与乐观锁-演道网

本网站用的阿里云ECS,推荐大家用。自己搞个学习研究也不错
业务逻辑的实现过程中,往往需要保证数据访问的排他性。因此,我们就需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改,这样的机制,在这里,也就是所谓的“锁”,即给我们选定的目标数据上锁,使其无法被其它程序修改。

Hibernate 支持两种锁机制:

1. 悲观锁(Pessimistic Locking)

从加载对象就开始锁定。修改过程中一直是锁。直到事务commit()提交后再解锁。

session.load(Info.class,”p003″,LockOptions.UPGRADE);

public class TestPessimisticLock extends TestCase {
    @Test
    public void testLock1(){
        Session session = null;
        try {
            session = HibernateUtil.getSession();//开始锁定,下面的testLock2不能执行
            session.beginTransaction();
            
            Info data = session.load(Info.class, "p003", LockOptions.UPGRADE);
            data.setName("1111111");
            
            session.getTransaction().commit();//执行以后才解锁,这时testLock2才可以执行
        }  
        catch (Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }
        finally{
            HibernateUtil.closeSession();
        }
    } 
    @Test
    public void testLock2(){
        Session session = null;
        try {
            session = HibernateUtil.getSession();
            session.beginTransaction();
            
            Info data = session.load(Info.class, "p003", LockOptions.UPGRADE);
            data.setName("2222222");
            
            session.getTransaction().commit();
        }  
        catch (Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }
        finally{
            HibernateUtil.closeSession();
        }
    } 
}

2. 乐观锁(Optimistic Locking)

并不是真的锁,是在提交时间进行冲突检测。把里面的内容与刚开始读取的内容对照一下,有问题就抛异常。相对于悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。 

悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个”version”字段来实现。 

 

乐观锁的工作原理 :

读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。 

配置:

1.在数据库表中加一个字段version

如果是数据库后加的version字段,那么实体类中必须要加上version并生成get、set方法

public class Info implements java.io.Serializable {

    private String code;
    private Nation nation;
    private String name;
    private Boolean sex;
    private Date birthday;
    private Set families = new HashSet(0);
    private Set works = new HashSet(0);
    private int version;//实体类中也要有version,并生成getter和setter

    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }

2.在映谢文件中配置 这里注意version的位置,一定是要放置在id的后面 

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-11 10:12:32 by Hibernate Tools 5.2.0.CR1 -->
<hibernate-mapping>
    <class name="com.itnba.maya.model.Info" table="info" catalog="mydb" optimistic-lock="version">
        <cache usage="read-only"/> 
        <id name="code" type="string">
            <column name="Code" length="50" />
            <generator class="assigned" />
        </id>
        <!-- 配置version,位置放在下面 -->
        <version name="version"></version>
<many-to-one name="nation" class="com.itnba.maya.model.Nation" fetch="select"> <column name="Nation" length="50" /> </many-to-one> <property name="name" type="string"> <column name="Name" length="50" /> </property> <property name="sex" type="java.lang.Boolean"> <column name="Sex" /> </property> <property name="birthday" type="timestamp"> <column name="Birthday" length="19" /> </property> </class> </hibernate-mapping>

配置完成后代码不用改变

由乐观锁引发的问题 

当两个不同的事务同时读取到一条数据并进行修改时,这个时候程序就会抛出org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)异常。 

这里同样有两种情况 

一种是两个不同的事务的情况 

@Test  
public void testTransation1(){  
    Session session1 = null;  
    Session session2 = null;  
    try{  
        session1 = HibernateUtil.getSession();  
        session2 = HibernateUtil.getSession();  
        Info info1= session1.load(Info.class, "p003");  
        Info info2 = session2.load(Info.class, "p003");  
        Transaction tx1 = session1.beginTransaction();  
        info1.setName("2222222"); 
        tx1.commit();  
        Transaction tx2 = session2.beginTransaction();  
        info2.setName("11111111");  
        tx2.commit();  
        System.out.println("事务2提交");  
    }catch(Exception e){  
        e.printStackTrace();  
    }finally{  
        if(session1 != null){  
            session1.close();  
        }  
        if(session2 != null){  
            session2.close();  
        }  
    }  
} 

事务2提交时发现version的值不一样,这个时候就会抛出org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)异常.

第二种情况是子事务的情况 

@Test  
public void testTransation2(){  
    Session session1 = null;  
    Session session2 = null;  
    try{  
        session1 = HibernateUtil.getSession();  
        session2 = HibernateUtil.getSession();  
        Info info1= session1.load(Info.class, "p003");  
        Info info2 = session2.load(Info.class, "p003");  
        Transaction tx1 = session1.beginTransaction();
        Transaction tx2 = session2.beginTransaction(); 
        info2.setName("11111111");   
        tx2.commit(); 
        info1.setName("2222222");   
        tx1.commit();
    }catch(Exception e){  
        e.printStackTrace();  
    }finally{  
        if(session1 != null){  
            session1.close();  
        }  
        if(session2 != null){  
            session2.close();  
        }  
    }  
}          

解决办法

1、捕获StaleObjectStateException异常,提示数据过时已被修改,让用户重新提交

2、尽量从业务方面去减小事务块,事务块越大,由乐观锁引起的问题的概率就越大

Hibernate3.1.2_中文文档PDF  http://www.linuxidc.com/Linux/2016-02/128462.htm

Hibernate学习入门教程  http://www.linuxidc.com/Linux/2015-08/121498.htm

在Hibernate中开启日志 http://www.linuxidc.com/Linux/2015-07/120499.htm

Hibernate+JUnit测试实体类生成数据库表  http://www.linuxidc.com/Linux/2015-07/120161.htm

Hibernate整体理解 http://www.linuxidc.com/Linux/2014-07/104405.htm

Hibernate的映射机制  http://www.linuxidc.com/Linux/2014-12/110265.htm

Hibernate利用@DynamicInsert和@DynamicUpdate生成动态SQL语句  http://www.linuxidc.com/Linux/2016-08/134619.htm

Struts2+Spring3+Hibernate3+MySQL简单登录实现  http://www.linuxidc.com/Linux/2017-02/140408.htm

Hibernate的简单示例  http://www.linuxidc.com/Linux/2016-11/136609.htm

Intellij IDEA 15 下新建 Hibernate 项目及添加配置  http://www.linuxidc.com/Linux/2016-09/135624.htm

Hibernate 的详细介绍请点这里
Hibernate 的下载地址请点这里

转载自演道,想查看更及时的互联网产品技术热点文章请点击http://go2live.cn

未经允许不得转载:演道网 » Hibernate 悲观锁与乐观锁-演道网

赞 (0)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册