导航

JavaYe

欢迎光临小站,喝口咖啡,品位Java,希望您喜欢JavaYe.COM 。

« 使用JavaRebel让Scala走向动态化(新闻快递)【原创】关于Spring中的HibernateTemplate的事务性 »

【原创】今天做了个奇怪的Hibernate事务试验



应用场景:现有一个表Article(帖子),其中有一个字段visit_amount表示这个帖子被浏览过多少次。
现在做一个实验,开两个线程做同一件事情,就是:取出原有的浏览次数,然后加一,再存回数据库。每个线程把这个动作重复10次。

设想的结果:如果浏览次数的初始值是0的话,那么程序运行完毕后,浏览次数应该增长到20。

Java代码
  1.   
  2. package com.javaye;   
  3.   
  4. import org.hibernate.LockMode;   
  5. import org.hibernate.Session;   
  6. import org.hibernate.Transaction;   
  7.   
  8. import com.javaye.models.Article;   
  9.   
  10. public class Main {   
  11.        
  12.   
  13.     private  static void update(){   
  14.         Session session = HibernateSessionFactory.getSession();   
  15.         Transaction tx =  session.beginTransaction();   
  16.         Article art = (Article) session.load(Article.class1);   
  17.         art.setVisitAmount(art.getVisitAmount()+1);   
  18.         session.save(art);   
  19.         tx.commit();   
  20.            
  21.            
  22.     }   
  23.        
  24.     private static void work(){   
  25.         for(int i=0;i<10;i++){   
  26.             System.out.println(Thread.currentThread().getName()+":"+(i+1)+"times.");   
  27.             update();   
  28.         }   
  29.     }   
  30.        
  31.     public static void main(String[] args) throws Exception{   
  32.         Thread t1 = new Thread(   
  33.             new Runnable(){   
  34.                 public void run(){   
  35.                     work();   
  36.                 }   
  37.             }   
  38.         );   
  39.            
  40.         Thread t2 = new Thread(   
  41.                 new Runnable(){   
  42.                     public void run(){   
  43.                         work();   
  44.                     }   
  45.                 }   
  46.         );   
  47.         t1.setName("Thread1");   
  48.         t2.setName("Thread2");   
  49.         t1.setDaemon(true);   
  50.         t2.setDaemon(true);   
  51.         t1.start();   
  52.         t2.start();   
  53.         t1.join();   
  54.         t2.join();   
  55.            
  56.     }   
  57. }  



上面是第一个版本,结果测试的结果发现没有实现事务的隔离性,每次的结果是随机的,要么是10要么是11或12。

然后,我进行了修改,加上了session.evict(art)来清空缓存,然后发现结果变得好一些了,但是结果并不总是20,有时候是19或18。真奇怪。

再后来,把load语句改为:
 

Java代码
  1. Article art = (Article) session.load(Article.class1,LockMode.UPGRADE);  



经过多次测试,结果总为20,实现了事务的隔离性。

最终work的代码如下:
 

Java代码
  1. package com.javaye;   
  2.   
  3. import org.hibernate.LockMode;   
  4. import org.hibernate.Session;   
  5. import org.hibernate.Transaction;   
  6.   
  7. import com.javaye.models.Article;   
  8.   
  9. public class Main {   
  10.        
  11.     private static void insert(){   
  12.         Session session = HibernateSessionFactory.getSession();   
  13.         Transaction tx = session.beginTransaction();   
  14.         Article art = new Article();   
  15.         art.setTitle("AAA");   
  16.         art.setVisitAmount(0);   
  17.         session.saveOrUpdate(art);   
  18.         tx.commit();   
  19.     }   
  20.        
  21.     private  static void update(){   
  22.         Session session = HibernateSessionFactory.getSession();   
  23.         Transaction tx =  session.beginTransaction();   
  24.         Article art = (Article) session.load(Article.class1,LockMode.UPGRADE);   
  25.         art.setVisitAmount(art.getVisitAmount()+1);   
  26.         session.save(art);   
  27.         tx.commit();   
  28.         session.evict(art);   
  29.            
  30.     }   
  31.        
  32.     private static void work(){   
  33.         for(int i=0;i<10;i++){   
  34.             System.out.println(Thread.currentThread().getName()+":"+(i+1)+"times.");   
  35.             update();   
  36.         }   
  37.     }   
  38.        
  39.     public static void main(String[] args) throws Exception{   
  40.         Thread t1 = new Thread(   
  41.             new Runnable(){   
  42.                 public void run(){   
  43.                     work();   
  44.                 }   
  45.             }   
  46.         );   
  47.            
  48.         Thread t2 = new Thread(   
  49.                 new Runnable(){   
  50.                     public void run(){   
  51.                         work();   
  52.                     }   
  53.                 }   
  54.         );   
  55.         t1.setName("Thread1");   
  56.         t2.setName("Thread2");   
  57.         t1.setDaemon(true);   
  58.         t2.setDaemon(true);   
  59.         t1.start();   
  60.         t2.start();   
  61.         t1.join();   
  62.         t2.join();   
  63.            
  64.     }   
  65. }  



查了一下文档,LockMode.UPGRADE是最高的锁级别了,如果换用其他的级别呢?我测试了LocMode.READ,发现还是不正确,用LockMode.WRITE的时候竟然抛异常。。大侠们谈谈看法吧:-)

  • quote 1.Y.F.
  • 非常专业!
    robot666 于 2008-5-22 20:25:46 回复
    呵呵,其实很业余,我在JavaEye上也发了这个贴,不过没人理我,所以就贴到自己的一亩三分地来了。Hehe
  • 2008-5-22 20:23:13 回复该留言
  • quote 3.GOODSPEED
  • LockMode.READ结果不正确是正常的,LockMode.WRITE抛异常应该是写法上有问题,多想想并发机制的处理,应该有答案
  • 2008-7-4 17:01:11 回复该留言

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Copyright 2007-2008 JavaYe.com. Some Rights Reserved.

Search

控制面板

  • [管理登录]  [给我留言]

最近发表