应用场景:现有一个表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的时候竟然抛异常。。大侠们谈谈看法吧:-)
分享到:
相关推荐
【hibernate事务管理机制】是指在使用Hibernate框架进行数据库操作时,如何管理和协调事务的一系列规则和策略。事务管理是确保数据一致性、完整性和并发控制的重要机制。 **悲观锁**是预防性的锁定策略,它假设并发...
Hibernate提供了LockMode类型的锁,如LockMode.READ、LockMode.WRITE和LockMode.UPGRADE,分别对应不同的锁定级别。 此外,Hibernate还支持读写分离和第二级缓存来优化并发性能。读写分离将读操作和写操作分散到...
对于基于Java Web的应用而言,Hibernate作为一款流行的ORM框架,提供了多种手段来解决并发问题。其中,“乐观锁”和“悲观锁”是最为常见且有效的两种机制。本文将深入探讨这两种锁的原理及应用场景,帮助开发者更好...
在Hibernate中,我们可以使用`setLockMode`方法对查询结果进行加锁,例如设置`LockMode.UPGRADE`,这将使Hibernate在执行SQL时添加`FOR UPDATE`子句,从而实现悲观锁。 接下来是乐观锁(Optimistic Locking)。与...
Hibernate支持的悲观锁模式有`LockMode.UPGRADE`(对应SQL的`for update`)和`LockMode.UPGRADE_NOWAIT`(Oracle特有的,用于立即返回等待超时的结果)。 **乐观锁(Optimistic Locking)** 乐观锁则相对乐观,它...
- **LockMode.UPGRADE_NOWAIT**:仅限Oracle数据库,使用`FOR UPDATE NOWAIT`子句来加锁。 #### 三、乐观锁(Optimistic Locking) ##### 3.1 定义 乐观锁基于一种假设:大多数并发操作都不会引起冲突。它通过比较...
Customer customer = (Customer) session.load(Customer.class, 1, LockMode.UPGRADE); ``` 乐观锁 乐观锁与数据库锁无关,在数据表中为数据添加版本字段,每次数据修改都会导致版本号+1。 例如,在 Hibernate 中...
- `LockMode.UPGRADE_NOWAIT`:Oracle特有的实现方式,使用`FOR UPDATE NOWAIT`子句实现锁定。 **4. 应用悲观锁的注意事项** - **锁定时机**:悲观锁必须在查询开始之前设置,即在Hibernate生成SQL语句之前设置,...
一、Hibernate事务管理 在数据库操作中,事务确保了数据的一致性和完整性。Hibernate提供了四种事务隔离级别:读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和串行化...
这种策略在数据库层面通常是通过`FOR UPDATE`子句实现,如Hibernate的`LockMode.UPGRADE`,在查询时附加此选项,可以确保数据在处理期间不会被其他事务修改。然而,悲观锁可能会导致大量等待,尤其在网络环境下,多...
如果需要锁定记录进行更新操作,可以使用 `session.refresh(entity, LockMode.UPGRADE)` 方法来锁定记录。例如: ```java session.refresh(user, LockMode.UPGRADE); ``` 这样,在执行完上述操作后,其他事务将...
在 Hibernate 中,悲观锁的实现方式有多种,例如使用 `LockMode.UPGRADE` 加锁方式,或者使用 `for update` 语句来锁定数据。在查询开始之前加锁,才会真正通过数据库的锁机制加锁处理。 二、乐观锁(Optimistic ...
Hibernate 实现悲观锁...在 `testPessimisticLock` 方法中,我们使用了 `LockMode.UPGRADE` 来加锁,以防止其他事务访问相同的数据。 Hibernate 的锁机制可以防止数据的更新和访问,它可以提高系统的安全性和一致性。
在 Hibernate 中,悲观锁是通过数据库级别的锁定机制实现的,例如使用 `LockMode` 类定义的不同锁定级别(如 `LockMode.UPGRADE`、`LockMode.UPGRADE_NOWAIT` 和 `LockMode.READ`)。 #### 2. Hibernate 工作原理及...
在Hibernate中,悲观锁主要通过`LockMode.UPGRADE`实现,即使用`SELECT ... FOR UPDATE`语句。 - 乐观锁:在读取数据时不加锁,只有在更新数据时才检查是否有其他事务在此期间修改了数据。通常通过版本号或时间戳...