`
yangxianjiangg
  • 浏览: 61248 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

对Hibernate的LockMode的进一步思考

阅读更多

让我们先来看看Hibernate的文档时怎么说的,关于LockMode:


LockMode FORCE
          Similiar to UPGRADE except that, for versioned entities, it results in a forced version increment.


LockMode NONE
          No lock required.


LockMode READ
          A shared lock. Objects in this lock mode were read from the database in the current transaction, rather than being pulled from a cache (注:也就是从数据库中读数据,绕过了Hibernate的Cache)


LockMode UPGRADE
          An upgrade lock.(注:相当于SQL语句select xxx from xxxx for update,也就是把事务的处理交给了数据库)

LockMode UPGRADE_NOWAIT
          Attempt to obtain an upgrade lock, using an Oracle-style select for update nowait.


LockMode WRITE
          A WRITE lock is obtained when an object is updated or inserted.This lock mode is for internal use only and is not a valid mode for load() or lock() (both of which throw exceptions if WRITE is specified). (注:不能在load的时候用,否则抛出异常)


不过,“纸上得来终觉浅,觉知此事要躬行”,博主做了下实验来比较这些“锁”的不同。

先看代码:

 

package com.javaye;   

import org.hibernate.LockMode;   
import org.hibernate.Session;   
import org.hibernate.Transaction;   

import com.javaye.models.Article;   

public class Main {   

private static void insert(){   
   Session session = HibernateSessionFactory.getSession();   
   Transaction tx = session.beginTransaction();   
   Article art = new Article();   
   art.setTitle("AAA");   
   art.setVisitAmount(0);   
   session.saveOrUpdate(art);   
   tx.commit();   
}   

private static void update(){   
   Session session = HibernateSessionFactory.getSession();   
   System.out.println("session:"+session.hashCode());   
   Transaction tx = session.beginTransaction();   
<SPAN style="COLOR: #ff0000">Article art = (Article) session.load(Article.class, 1,LockMode.UPGRADE);   
   System.out.println("             loaded");</SPAN>   
<SPAN style="COLOR: #0000ff">art.setVisitAmount(art.getVisitAmount()+1);</SPAN>   
   session.save(art);   
   tx.commit();   
   session.evict(art);   
     
}   

private static void work(){   
   for(int i=0;i<10;i++){   
    System.out.println(Thread.currentThread().getName()+":"+(i+1)+"times.");   
    update();   
   }   
}   

public static void main(String[] args) throws Exception{   
   Thread t1 = new Thread(   
    new Runnable(){   
     public void run(){   
      work();   
     }   
    }   
   );   
     
   Thread t2 = new Thread(   
     new Runnable(){   
      public void run(){   
       work();   
      }   
     }   
   );   
   t1.setName("Thread1");   
   t2.setName("Thread2");   
   t1.setDaemon(true);   
   t2.setDaemon(true);   
   t1.start();   
   t2.start();   
   t1.join();   
   t2.join();   
     
}   
} 

package com.javaye;

import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.javaye.models.Article;

public class Main {

private static void insert(){
   Session session = HibernateSessionFactory.getSession();
   Transaction tx = session.beginTransaction();
   Article art = new Article();
   art.setTitle("AAA");
   art.setVisitAmount(0);
   session.saveOrUpdate(art);
   tx.commit();
}

private static void update(){
   Session session = HibernateSessionFactory.getSession();
   System.out.println("session:"+session.hashCode());
   Transaction tx = session.beginTransaction();
Article art = (Article) session.load(Article.class, 1,LockMode.UPGRADE);
   System.out.println("             loaded");
art.setVisitAmount(art.getVisitAmount()+1);
   session.save(art);
   tx.commit();
   session.evict(art);

}

private static void work(){
   for(int i=0;i<10;i++){
    System.out.println(Thread.currentThread().getName()+":"+(i+1)+"times.");
    update();
   }
}

public static void main(String[] args) throws Exception{
   Thread t1 = new Thread(
    new Runnable(){
     public void run(){
      work();
     }
    }
   );

   Thread t2 = new Thread(
     new Runnable(){
      public void run(){
       work();
      }
     }
   );
   t1.setName("Thread1");
   t2.setName("Thread2");
   t1.setDaemon(true);
   t2.setDaemon(true);
   t1.start();
   t2.start();
   t1.join();
   t2.join();

}
}

 
这是一个多线程程序,每个线程都会从数据库中取出visit_amount,然后加一,再存回数据库,每个线程重复10遍。

     请注意蓝色的部分,我们在这里设一个断点,那么用Eclipse调试的时候,到达这个断点的线程就会停下来,由于它的事务还没有commit(),LockMode.UPGRADE的锁就还没有释放,那么另外一个线程中事务就会在load的时候因为不能获得锁而阻塞,那么理论上我们只会看到只有一句“    loaded ”输出。 实验结果证明了我的猜想,LockMode.UPGRADE的情况下,如果一个事务获得了锁,即使另外的事务想读取数据也是不行的,必须等待锁的释放。

    那么,改写数据可以吗?笔者又做了一个实验,打开MySQL Query Browser,直接生改数据库,把visit_amount字段的值硬生生改过来,结果发现提交的时候就阻塞了,MySQL的海豚标志一个劲的游泳,这说明,LockMode.UPGRADE级别的锁不是由Hibernate控制的,而是由数据库控制的。

    再试一试LockeMode.Read,断点还是设在原来的位置,发现有两次“      loaded”输出,证明两个事务可以同时读取这条数据,那么这个锁有什么作用呢?根据我实验的结果,似乎只是为了绕过cache,从数据库直接读取。为了证明我的猜想,我直接通过MySQL Query Browser更改了visit_amount,调试发现,Hibernate是从数据库中读取的新值,而不是cache中的老值。

    最后在补充一点,LockMode.UPGRADE加锁是有超时时间的,如果加锁后超过一定的时间不commit,Hibernate会抛出异常。

分享到:
评论

相关推荐

    hibernate3.2+cglib2.2架包

    8. **实体状态管理**:了解对象的瞬时、持久、脱管和临时状态对正确使用Hibernate至关重要。 9. **事件和拦截器**:Hibernate允许注册事件监听器或拦截器,以便在特定操作前后执行自定义逻辑。 10. **类型转换**:...

    Hibernate 事务和并发控制

    Hibernate提供了LockMode类型的锁,如LockMode.READ、LockMode.WRITE和LockMode.UPGRADE,分别对应不同的锁定级别。 此外,Hibernate还支持读写分离和第二级缓存来优化并发性能。读写分离将读操作和写操作分散到...

    hibernate事务管理机制.doc

    在Hibernate中,悲观锁可以通过`LockMode`进行设置,如`LockMode.WRITE`、`LockMode.UPGRADE`等。例如,使用`session.get()`或`session.createQuery().setLockMode()`方法可以在查询时加锁。`LockMode.UPGRADE`会...

    hibernate的乐观锁和悲观锁

    - `LockMode.WRITE`:Hibernate在插入或更新记录时自动获取。 - `LockMode.READ`:Hibernate在读取记录时自动获取。 - `LockMode.UPGRADE`:利用数据库的`FOR UPDATE`子句加锁。 - `LockMode.UPGRADE_NOWAIT`:...

    hibernate乐观锁和悲观锁学习

    在Hibernate中,我们可以使用`setLockMode`方法对查询结果进行加锁,例如设置`LockMode.UPGRADE`,这将使Hibernate在执行SQL时添加`FOR UPDATE`子句,从而实现悲观锁。 接下来是乐观锁(Optimistic Locking)。与...

    Hibernate悲观锁和乐观锁的实现

    2. **LockMode**: Hibernate提供了LockMode类,可以通过Session的`lock()`或`update()`方法,指定LockMode.PESSIMISTIC_WRITE或LockMode.PESSIMISTIC_READ来获取悲观锁。 **乐观锁**(Optimistic Lock)则相对乐观...

    Hibernate5用户手册中文版

    2. Domain Model(域模型)章节,着重讲解了Hibernate如何通过POJO模型来表示业务对象,并且对POJO模型中的类特性提出了具体要求,例如无参构造器、标识属性、非final类的使用、持久化属性的getter和setter方法以及...

    Hibernate乐观锁和悲观锁分析

    Hibernate支持的悲观锁模式有`LockMode.UPGRADE`(对应SQL的`for update`)和`LockMode.UPGRADE_NOWAIT`(Oracle特有的,用于立即返回等待超时的结果)。 **乐观锁(Optimistic Locking)** 乐观锁则相对乐观,它...

    hibernate 对事务并发处理

    Hibernate 对事务并发处理 在 Hibernate 中,对事务并发处理是非常重要的, especialmente 在多用户环境中。事务处理的目的是为了保证数据的可靠性和一致性。 事务四个特性 ACID 1. 原子性(Atomicity):事务...

    Hibernate查询解决方案

    - `load(Class&lt;T&gt; theClass, Serializable id, LockMode lockMode)`:根据类类型、主键和锁定模式加载对象。 - `load(Object object, Serializable id)`:根据对象和主键加载对象。 - **`createQuery` 方法**:...

    hibernate事务,并发及缓存管理实例

    Hibernate还支持LockMode,包括READ、WRITE、UPGRADE和OPTIMISTIC等,以适应不同级别的并发控制需求。 三、缓存管理 缓存技术可以显著提升应用性能,减少数据库访问。Hibernate的缓存分为一级缓存和二级缓存。一级...

    Hibernate缓存深入详解 from ITEye

    为了保证多线程环境下的数据一致性,Hibernate提供了缓存同步机制,如LockMode和Locking Strategy。通过这些机制,可以在并发环境下控制对缓存的访问,防止脏读、不可重复读和幻读等问题。 **七、最佳实践** 1. **...

    Hibernate Developer Guide

    Hibernate是一款开源的对象关系映射(Object Relational Mapping,简称ORM)框架,它为Java应用提供了对关系型数据库的高效持久化支持。Hibernate的主要特点包括简化了数据持久化的复杂度,并且支持多种数据库。 ##...

    Hibernate锁机制_悲观锁和乐观锁

    在 Hibernate 中,悲观锁的实现方式有多种,例如使用 `LockMode.UPGRADE` 加锁方式,或者使用 `for update` 语句来锁定数据。在查询开始之前加锁,才会真正通过数据库的锁机制加锁处理。 二、乐观锁(Optimistic ...

    Hibernate5 的用户手册中文版

    锁章节讲解了乐观锁和悲观锁的使用和管理,包括乐观锁的版本号和时间戳机制,悲观锁的使用以及LockMode类的介绍。 9. Fetching(抓取): 抓取章节介绍了抓取策略,包括不抓取、通过查询动态抓取以及通过配置文件...

    Hibernate中Criteria的完整用法

    对于 Criteria 还可以设置 FlushModel(冲刷 Session 的方式)和 LockMode(数据库锁模式)。 Criterion 是 Criteria 的查询条件。Criteria 提供了 add(Criterion criterion) 方法来添加查询条件。Criterion 接口的...

    Hibernate的乐观锁与悲观锁

    在上述代码中,`query.setLockMode`方法用于对查询结果中的每一行数据设置悲观锁。Hibernate会在执行查询时生成如下SQL语句: ```sql SELECT tuser0_.id AS id, tuser0_.name AS name, tuser0_.group_id AS group_...

    数据库事务、hibernate悲观锁和乐观锁

    在Hibernate框架中,悲观锁通过`LockMode.PESSIMISTIC_READ`和`LockMode.PESSIMISTIC_WRITE`来实现。`PESSIMISTIC_READ`通常用于读取数据时避免其他事务更新,而`PESSIMISTIC_WRITE`则更严格,不仅阻止更新,也阻止...

Global site tag (gtag.js) - Google Analytics