悲观锁:
读取数据的时候对记录加锁,直到提交数据更新后解锁。这样保证更新数据的时候,原来读取的数据和数据库一致。但加锁时间过长,以致长时间其它线程不能读取数据,造成性能急剧下降。
乐观锁:
从数据库读取数据,在写数据的时候加锁,更新数据库后解锁。在保存之前会检查之前读多的数据是不是最新的,如果不是就拒绝保存并抛异常。
Hibernate提供了3种乐观锁实现:
a. 版本控制
b. 时间戳
c. 为遗留项目添加乐观锁
a. 版本控制:
描述: 读取数据的时候会记录版本号,在更新的时候检查这个版本号是否和数据库相同,不同表示在这段时间内数据库被更新过。
实现:在映射文件(如User.hbm.xml)id节点的后面,加上:
<version name="version" />
这里的type默认是integer的。
b. 时间戳:
描述:和版本控制类似。有个缺点是时间戳精度的原因,可能会造成问题。
实现:和版本控制类似:
<timestamp name="timestamp" />
c. 为遗留项目添加乐观锁:
描述:遗留项目,无法使用上面两种方式配置乐观锁。
实现:在<class>标签上添加optimistic-lock属性:
<class name="com.john.domain.User" optimistic-lock="all">
</class>
all表示让该记录的所有字段都为版本控制信息。
1. 乐观锁测试
<hibernate-mapping package="com.john.hibernate.domain">
<class name="User" table="user">
<id name="id">
<generator class="native"/>
</id>
<!--<version name="version" />-->
<!--<timestamp name="timestamp" />-->
...
</class>
</hibernate-mapping>
public class User {
private int id;
//private Integer ver;
//private Date timestamp;
private String username;
private Date birthday;
private float money;
// Setters and getters are omitted
}
public class VersionTest {
public static void main(String[] args) {
User user = new User();
user.setUsername("john");
user.setMoney(40000);
AddUser(user); // the method is omitted
updateUser();
}
// The try-catch and finally blocks are omitted
static void updateUser() {
Session s1 = HibernateUtil.getSession();
Session s2 = HibernateUtil.getSession();
System.out.println(s1 == s2); // false
Transaction tx = s1.beginTransaction();
User user1 = (User) s1.get(User.class, 1);
Transaction tx2 = s2.beginTransaction();
User user2 = (User) s2.get(User.class, 1);
user1.setMoney(user1.getMoney() + 10000);
user2.setMoney(user2.getMoney() + 20000);
tx.commit();
tx2.commit();
}
完成后数据库的money值是60000,没有抛异常,tx2把tx提交的数据给覆盖了。
如果把类中的ver字段和映射文件中的<version .../>解注释,运行结果:
money值是50000,抛异常:org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
也可以解注释timestamp字段和<timestamp .../>,运行效果相同。
2. 在一个session里最多只能有一个transaction
org.hibernate.jdbc.getTransaction方法:
public Transaction getTransaction() throws HibernateException {
if (hibernateTransaction==null) {
hibernateTransaction = owner.getFactory().getSettings()
.getTransactionFactory()
.createTransaction( this, owner );
}
return hibernateTransaction;
}
static void testTransaction() {
Session s = HibernateUtil.getSession();
Transaction tx1 = s.beginTransaction();
Transaction tx2 = s.beginTransaction();
System.out.println(tx1 == tx2); // true
}
如果hibernateTransaction为空,使用工厂模式创建一个;否则返回已创建过的。
分享到:
相关推荐
#### 一、悲观锁与乐观锁的概念 悲观锁和乐观锁是计算机科学中用于处理并发控制的两种不同策略,它们主要应用于多线程环境下数据的一致性和完整性保护。两种锁的设计哲学反映了对数据并发访问时的不同预期。 **...
### Hibernate的乐观锁与悲观锁 #### 一、引言 在并发环境下,尤其是在金融、电商等业务场景中,确保数据的一致性和完整性至关重要。**Hibernate**作为一种流行的Java持久层框架,提供了多种机制来处理并发控制...
【描述】:“面试必备之乐观锁与悲观锁.pdf”涉及的是并发控制中的两种重要锁机制——悲观锁和乐观锁,它们是多线程环境下确保数据一致性的重要手段。 【标签】:“求职面试 多线程” 【正文】: 悲观锁和乐观锁...
乐观锁和悲观锁是数据库事务控制...了解和掌握乐观锁与悲观锁的原理和应用场景,对于提升面试者的数据库管理技能和解决并发问题的能力至关重要。在面试中,深入探讨这些话题将有助于展示自己的专业水平和问题解决能力。
乐观锁与悲观锁各有优缺点。悲观锁适合于高并发写操作的场景,可以防止丢失更新,但可能导致死锁问题。乐观锁则适用于写操作较少,且可以接受偶尔的冲突重试的情况,它减少了锁的开销,提升了系统的吞吐量。然而,...
"面试必备之乐观锁与悲观锁" 在多线程编程中,锁机制是必不可少的一部分,锁机制可以防止多个线程同时访问共享资源,避免数据不一致和混乱的情况。锁机制可以分为悲观锁和乐观锁两种,下面我们将详细介绍这两种锁...
面试资源乐观锁与悲观锁
Java 架构面试中,乐观锁与悲观锁是两个重要的并发控制概念,它们在多线程环境下用于确保数据的一致性。理解这两种锁对于开发者来说至关重要,特别是在高并发的系统设计中。 **悲观锁**是一种保守的并发控制策略,...
除了上述的乐观锁和悲观锁实现技巧之外,ThinkPHP框架还提供了其他很多与数据操作和事务管理相关的功能和技巧。例如,在ThinkPHP中,可以使用事务控制相关的类和方法,如mysqli的transaction方法开始事务,commit...
【Hibernate乐观锁与悲观锁详解】 在开发过程中,尤其是在并发环境下,确保数据的一致性和完整性至关重要。Hibernate,作为Java领域广泛使用的ORM框架,提供了一种处理并发数据访问冲突的手段,那就是锁机制。主要...
1. **事务隔离级别**:乐观锁和悲观锁与数据库的事务隔离级别密切相关。例如,读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和串行化(SERIALIZABLE)这四种隔离级别都会...