`
fxsjy
  • 浏览: 35588 次
  • 性别: 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来管理事务导致的......

相关推荐

    hibernate事务管理机制.doc

    【hibernate事务管理机制】是指在使用Hibernate框架进行数据库操作时,如何管理和协调事务的一系列规则和策略。事务管理是确保数据一致性、完整性和并发控制的重要机制。 **悲观锁**是预防性的锁定策略,它假设并发...

    Hibernate 事务和并发控制

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

    hibernate的乐观锁和悲观锁

    对于基于Java Web的应用而言,Hibernate作为一款流行的ORM框架,提供了多种手段来解决并发问题。其中,“乐观锁”和“悲观锁”是最为常见且有效的两种机制。本文将深入探讨这两种锁的原理及应用场景,帮助开发者更好...

    hibernate乐观锁和悲观锁学习

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

    Hibernate乐观锁和悲观锁分析

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

    Hibernate的乐观锁与悲观锁

    - **LockMode.UPGRADE_NOWAIT**:仅限Oracle数据库,使用`FOR UPDATE NOWAIT`子句来加锁。 #### 三、乐观锁(Optimistic Locking) ##### 3.1 定义 乐观锁基于一种假设:大多数并发操作都不会引起冲突。它通过比较...

    hibernate 对事务并发处理

    Customer customer = (Customer) session.load(Customer.class, 1, LockMode.UPGRADE); ``` 乐观锁 乐观锁与数据库锁无关,在数据表中为数据添加版本字段,每次数据修改都会导致版本号+1。 例如,在 Hibernate 中...

    Java 中的悲观锁和乐观锁的实现

    - `LockMode.UPGRADE_NOWAIT`:Oracle特有的实现方式,使用`FOR UPDATE NOWAIT`子句实现锁定。 **4. 应用悲观锁的注意事项** - **锁定时机**:悲观锁必须在查询开始之前设置,即在Hibernate生成SQL语句之前设置,...

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

    一、Hibernate事务管理 在数据库操作中,事务确保了数据的一致性和完整性。Hibernate提供了四种事务隔离级别:读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和串行化...

    Hibernate悲观锁与乐观锁

    这种策略在数据库层面通常是通过`FOR UPDATE`子句实现,如Hibernate的`LockMode.UPGRADE`,在查询时附加此选项,可以确保数据在处理期间不会被其他事务修改。然而,悲观锁可能会导致大量等待,尤其在网络环境下,多...

    hibernate存取oracle的clob

    如果需要锁定记录进行更新操作,可以使用 `session.refresh(entity, LockMode.UPGRADE)` 方法来锁定记录。例如: ```java session.refresh(user, LockMode.UPGRADE); ``` 这样,在执行完上述操作后,其他事务将...

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

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

    Hibernate实现悲观锁和乐观锁代码介绍

    Hibernate 实现悲观锁...在 `testPessimisticLock` 方法中,我们使用了 `LockMode.UPGRADE` 来加锁,以防止其他事务访问相同的数据。 Hibernate 的锁机制可以防止数据的更新和访问,它可以提高系统的安全性和一致性。

    struts+spring+hibernate资料

    在 Hibernate 中,悲观锁是通过数据库级别的锁定机制实现的,例如使用 `LockMode` 类定义的不同锁定级别(如 `LockMode.UPGRADE`、`LockMode.UPGRADE_NOWAIT` 和 `LockMode.READ`)。 #### 2. Hibernate 工作原理及...

    hibernate锁实验,以及解决方案

    在Hibernate中,悲观锁主要通过`LockMode.UPGRADE`实现,即使用`SELECT ... FOR UPDATE`语句。 - 乐观锁:在读取数据时不加锁,只有在更新数据时才检查是否有其他事务在此期间修改了数据。通常通过版本号或时间戳...

Global site tag (gtag.js) - Google Analytics