`
hlbng
  • 浏览: 175029 次
  • 性别: 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();
  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架包

    内含hibernate3.2与修复java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.(Z)V 的错误的cglib2.2

    Hibernate悲观锁和乐观锁实例详解

    主要介绍了Hibernate悲观锁和乐观锁实例详解,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下

    南大通用GBase8s数据库锁监控及调整.docx

    通过监控数据库实例的锁使用情况,活跃锁的个数、死锁等信息,调整锁个数...1) onstat -k 监控当前活跃锁的个数,参照此设置LOCKS、DEF_TABLE_LOCKMODE参数,避免锁粒度太大、锁个数太多,浪费内存资源,从而影响性能。

    jdbc基础和参考

    Hibernate:ORM的中间件,或者说是实现了ORM的一个框架,对JDBC做了轻量级的封装。 ORM:使用元数据信息来描述对象和数据库之间的关系,并且能够自动实现java中持久化对象到关系型数据库中表的映射 脏检查:自动对...

    数据库锁表问题解决方法

    当某个数据库用户在数据库中插入、更新、删除一个表的数据,或者增加一个表的主键时或者表的索引时,常常会出现ora-00054:resource busy and acquire with nowait specified这样的错误。 主要是因为有事务正在执行...

    Android实现九宫格手势解锁

    本文为大家分享了Android九宫格手势解锁的具体代码,供... LockMode lockMode = (LockMode) getIntent().getSerializableExtra(Config.INTENT_SECONDACTIVITY_KEY); //是否显示手势的方向箭头 lv_lock.setShow(false)

    事务队列等待(TxEnqueue)深入分析——记录锁

    对于插入操作,数据在未提交之前对其他事务是“不可见”的,因而不会导致TX等待。这一类的TX锁是比较容易鉴别的——只有这类锁的模式(mode)是6(即排它锁,exclusive)。通过v$lock很容易鉴定出来:可以看到,...

    Python Sqlalchemy如何实现select for update

    sqlalchemy 对于行级锁有两种实现方式,with_lockmode(self, mode): 和 with_for_update(self, read=False, nowait=False, of=None),前者在sqlalchemy 0.9.0 被废弃,用后者代替。所以我们使用with_for_update ! 看...

Global site tag (gtag.js) - Google Analytics