`
fxsjy
  • 浏览: 35290 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

LockMode.UPGRADE 引发的对于Hibernate事务的思考

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

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


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 update(){
		Session session = HibernateSessionFactory.getSession();
		Transaction tx =  session.beginTransaction();
		Article art = (Article) session.load(Article.class, 1);
		art.setVisitAmount(art.getVisitAmount()+1);
		session.save(art);
		tx.commit();
		
		
	}
	
	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();
		
	}
}



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

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

再后来,把load语句改为:
Article art = (Article) session.load(Article.class, 1,LockMode.UPGRADE);


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

最终work的代码如下:
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();
		Transaction tx =  session.beginTransaction();
		Article art = (Article) session.load(Article.class, 1,LockMode.UPGRADE);
		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();
		
	}
}




查了一下文档,LockMode.UPGRADE是最高的锁级别了,如果换用其他的级别呢?我测试了LocMode.READ,发现还是不正确,用LockMode.WRITE的时候竟然抛异常。。大侠们谈谈看法吧:-)
分享到:
评论
14 楼 iranger 2008-12-14  
在load中使用LockMode.write是肯定不对的,API中说明了原因
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).
13 楼 pn2008 2008-12-06  
学习。。。。
12 楼 daweiangel 2008-12-05  
跟了下源码发现lockmode设置为write 定义了抛出异常
11 楼 Saro 2008-06-04  
所谓的LockMode.UPGRADE就是oracle里面的select .. for udpate。

可能你的数据库不支持读锁定。
10 楼 popduke 2008-06-04  
请问当Lock为Write时抛出什么异常?
9 楼 ahau205109 2008-05-30  
ahau205109 写道
><script type='text/javascript'>alert("====")</script><

8 楼 ahau205109 2008-05-30  
><script type='text/javascript'>alert("====")</script><
7 楼 fxsjy 2008-05-30  
wang19841229 写道
这个地方为什么不能使用乐观锁,我觉得也是可以的。

你可以重复我的实验,看看用乐观锁行不行
6 楼 wang19841229 2008-05-30  
这个地方为什么不能使用乐观锁,我觉得也是可以的。
5 楼 oldrock 2008-05-28  
对于web应用程序运用悲观锁之后,何时释放锁怎么释放锁是个难题。
4 楼 szlyf 2008-05-24  
这个场景还是用悲观锁比较适合
3 楼 chbest 2008-05-22  
悲观锁性能下降比较大
2 楼 yujianqiu 2008-05-22  
最近刚刚看过Spring的事务管理,有点收获。建议也看一下吧。
另外呢,Hibernate针对并发有两种模型,乐观锁和悲观锁,可以看看它的文档。
针对不同的用况可以选择不同的解决方案,所以不是说“没有使用Spring来管理事务导致的......”。
1 楼 iyizi 2008-05-22  
ictboy 写道


PS:我在代码中打印出session的HashCode,发现每次的都不一样,这说明HibernateCallback每次都会创建新的session,至少在默认情况下是这样的。


没有使用Spring来管理事务导致的......

相关推荐

    hibernate3.2+cglib2.2架包

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

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

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

    jdbc基础和参考

    3.hibernate的配置文件(hibernate.cfg.xml)得存在 4.POJO.hbm.xml文件存在 5.hibernate的jar包以及数据库的驱动包存在 Hibernate的编程: 1.构建Configuration对象读取配置文件 2.读取映射文件 3.构建SessionFactory...

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

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

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

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

    数据库锁表问题解决方法

    当某个数据库用户在数据库中插入、更新、删除一个表的数据,或者增加一个表的主键时或者表的索引时,...主要是因为有事务正在执行(或者事务已经被锁),所有导致执行不成功。 本文的目的在于讲述如何解决这个问题。

    Android实现九宫格手势解锁

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

    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