Hibernate中悲观锁和乐观锁

我们在使用Hibernate中经常用到当多个人对同一数据同时进行修改的时候,会发生脏数据,造成数据的不一致性,解决办法是可以通过悲观锁和乐观锁来实现。

 

Hibernate悲观锁:在数据有加载的时候就给其进行加锁,直到该锁被释放掉,其他用户才可以进行修改,优点:数据的一致性保持得很好,缺点:不适合多个用户并发访问。当一个锁住的资源不被释放掉的时候,这个资源永远不会被其他用户进行修改,容易造成无限期的等待。

 

Hibernate乐观锁:就是在对数据进行修改的时候,对数据才去版本或者时间戳等方式来比较,数据是否一致性来实现加锁。优点比较好。

 

一、在Hibernate悲观锁中,只要在加载的时候,才去session中的load方法,进行枷锁,session.load(****.class,1,LockMode.UPDATE);

 

Hibernate将事务管理委托给底层的JDBC或者JTA,默认是基于JDBC Transaction的。Hibernate支持“悲观锁(Pessimistic Locking)”和“乐观锁(Optimistic Locking)”。

Hibernate悲观锁对数据被外界修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。Hibernate悲观锁的实现,往往依靠数据库提供的锁机制。Hibernate通过使用数据库的for update子句实现了悲观锁机制。

 

Hibernate的加锁模式有:

 

1. LockMode.NONE:无锁机制

 

2. LockMode.WRITE:Hibernate在Insert和Update记录的时候会自动获取

 

3. LockMode.READ:Hibernate在读取记录的时候会自动获取

 

4. LockMode.UPGRADE:利用数据库的for update子句加锁

 

5. LockMode.UPGRADE_NOWAIT:Oracle的特定实现,利用Oracle的for update nowait子句实现加锁

 

 

二、乐观锁大多是基于数据版本(Version)记录机制实现。Hibernate在其数据访问引擎中内置了Hibernate乐观锁实现,可以通过class描述符的optimistic-lock属性结合version描述符指定。optimistic-lock属性有如下可选取值:

 

 

1. none:无乐观锁

 

2. version:通过版本机制实现乐观锁

 

3. dirty:通过检查发生变动过的属性实现乐观锁

 

4. all:通过检查所有属性实现乐观锁

 

例子:

1)Hibernate悲观锁:

 

1>POJO类

public class PersimisticLocking {  
 private int id;  
   
 private String Item;  
   
 private int price;  
//省略setter、getter方法  
} 

 2>、POJO类的映射文件

<?xml version="1.0"?> 
 <!DOCTYPE hibernate-mapping PUBLIC   
     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
 <hibernate-mapping package="org.apple.hibernate"> 
     <class name="PersimisticLocking" table="t_persimisticLocking"> 
         <id name="id"> 
             <generator class="native"/> 
         </id> 
        <property name="item"/> 
        <property name="price"/> 
    </class> 
</hibernate-mapping>

 3>、加载测试方法

public void testLoad1()  
     {  
         Session session = null;  
         try {  
             session = HibernateUtil.getSession();  
             session.beginTransaction();  
             OptimisticLocking o = (OptimisticLocking)session.load(OptimisticLocking.class, 1);  
             System.out.println("o.item="+o.getItem());  
             System.out.println("o.price="+o.getPrice());  
            System.out.println("o.version="+o.getVersion());  
            o.setPrice(o.getPrice()-10);  
            session.update(o);  
            session.beginTransaction().commit();  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
            session.beginTransaction().rollback();  
        }finally{  
            HibernateUtil.closeSession(session);  
        }  
          
    } 

 可以设置另外类似的方法,不枷锁,先对上面的测试代码设置断点,点debug一部分,再运行不枷锁的,可以看到,如果上面方法不释放锁的话,下面的数据就会造成无限期的等待。

 

2、Hibernate乐观锁:

 

1>在悲观锁的基础上加入private int version;和相关的setter、getter方法。

 

2>映射文件配置在class标签里面加入optimistic-lock="version",然后在的id标签后面加入<version name="version"/>

 

3>测试方法:

public void testLoad1()  
     {  
         Session session = null;  
         try {  
             session = HibernateUtil.getSession();  
             session.beginTransaction();  
             OptimisticLocking o = (OptimisticLocking)session.load(OptimisticLocking.class, 1);  
             System.out.println("o.item="+o.getItem());  
             System.out.println("o.price="+o.getPrice());  
            System.out.println("o.version="+o.getVersion());  
            o.setPrice(o.getPrice()-10);  
            session.update(o);  
            session.beginTransaction().commit();  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
            session.beginTransaction().rollback();  
        }finally{  
            HibernateUtil.closeSession(session);  
        }  
          
    } 

 在初始数据的时候,version为0,在没更新一次version都会在原来的基础上加1,通过version的版本来实现Hibernate乐观锁。

在上面的测试方法里面复制成另外一个方法,对上面的方法进行设置断点,然后单步调试几部,到NO.11行的时候暂停,此时对复制的另外方法运行,然后再运行完上面的方法,就会抛出异常,所以,在实际的项目开发中,可以通过对异常进行出来,这样就会实现并发访问。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hibernate可以使用悲观锁乐观锁来控制多个线程同时访问同一条记录时的并发性问题。 实现悲观锁的方法是,在Hibernate的查询语句使用“for update”语句,例如: ``` Session session = sessionFactory.getCurrentSession(); Transaction tx = session.beginTransaction(); try { Item item = (Item) session.get(Item.class, itemId, LockMode.UPGRADE); item.setPrice(newPrice); session.update(item); tx.commit(); } catch (Exception e) { tx.rollback(); throw e; } ``` 在这个例子,我们使用了LockMode.UPGRADE参数来获取悲观锁,这会在数据库将该行记录锁定,直到事务提交或回滚为止。 要实现乐观锁,可以使用Hibernate的@Version注解来定义一个版本号属性,例如: ``` @Entity public class Item { @Id private Long id; private String name; private double price; @Version private int version; // getters and setters } ``` 在使用乐观锁的代码,我们首先获取实体对象,修改实体对象的属性值,然后执行更新操作,例如: ``` Session session = sessionFactory.getCurrentSession(); Transaction tx = session.beginTransaction(); try { Item item = (Item) session.get(Item.class, itemId); item.setPrice(newPrice); session.update(item); tx.commit(); } catch (StaleObjectStateException e) { tx.rollback(); throw new OptimisticLockException("The item has been updated by another transaction", e); } catch (Exception e) { tx.rollback(); throw e; } ``` 在这个例子,如果在我们修改实体对象的属性值后,有另一个事务已经修改了该实体对象,那么我们就会捕获到StaleObjectStateException异常,这时我们就可以回滚事务并抛出一个OptimisticLockException异常,提示用户该实体对象已经被其他事务修改过了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值