Hibernate--LockMode

http://blog.csdn.net/inter_sky/article/details/2912230

让我们先来看看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的时候用,否则抛出异常)



LockMode.NONE :有缓存用缓存,没缓存则从数据库读 
LockMode.READ :直接从数据库读,不使用缓存数据 
LockMode.WRITE :在insert update数据的时候,HIBERNATE内部使用的。 
以上3种均为HIBERNATE级别的锁,也就是缓存级别的锁。 

下面2种为数据库级别的锁: 
LockMode.UPGRADE:相当于SQL语句select for update,被select的数据都被数据库锁住了,不能被其他事务修改。 
LockMode. UPGRADE_NOWAIT :是ORACLE数据库特有的select for update nowait

 

上面这两种锁机制是我们在应用层较为常用的,加锁一般通过以下方法实现:
Criteria.setLockMode
Query.setLockMode
Session.lock
注意,只有在查询开始之前(也就是Hiberate 生成SQL 之前)设定加锁,才会
真正通过数据库的锁机制进行加锁处理,否则,数据已经通过不包含for update
子句的Select SQL加载进来,所谓数据库加锁也就无从谈起。




Hibernate 在其数据访问引擎中内置了乐观锁实现。如果不用考虑外部系统对数
据库的更新操作,利用Hibernate提供的透明化乐观锁实现,将大大提升我们的
生产力。
Hibernate中可以通过class描述符的optimistic-lock属性结合version
描述符指定。
现在,我们为之前示例中的TUser加上乐观锁机制。
Hibernate Developer’s Guide Version 1.0
September 2, 2004 So many open source projects. Why not Open your Documents?
1. 首先为TUser的class描述符添加optimistic-lock属性:

<class
name="org.hibernate.sample.TUser"
table="t_user"
dynamic-update="true"
dynamic-insert="true"
optimistic-lock="version"
>
……

optimistic-lock属性有如下可选取值:
Ø none
无乐观锁
Ø version
通过版本机制实现乐观锁
Ø dirty
通过检查发生变动过的属性实现乐观锁
Ø all
通过检查所有属性实现乐观锁
其中通过version实现的乐观锁机制是Hibernate官方推荐的乐观锁实现,同时也
是Hibernate中,目前唯一在数据对象脱离Session发生修改的情况下依然有效的锁机
制。因此,一般情况下,我们都选择version方式作为Hibernate乐观锁实现机制。






 

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会抛出异常。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值