`

乐观锁与悲观锁

阅读更多
悲观锁
  读取数据的时候对记录加锁,直到提交数据更新后解锁。这样保证更新数据的时候,原来读取的数据和数据库一致。但加锁时间过长,以致长时间其它线程不能读取数据,造成性能急剧下降。

乐观锁
  从数据库读取数据,在写数据的时候加锁,更新数据库后解锁。在保存之前会检查之前读多的数据是不是最新的,如果不是就拒绝保存并抛异常。

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为空,使用工厂模式创建一个;否则返回已创建过的。
分享到:
评论

相关推荐

    面试必备之乐观锁与悲观锁.pdf

    #### 一、悲观锁与乐观锁的概念 悲观锁和乐观锁是计算机科学中用于处理并发控制的两种不同策略,它们主要应用于多线程环境下数据的一致性和完整性保护。两种锁的设计哲学反映了对数据并发访问时的不同预期。 **...

    Hibernate的乐观锁与悲观锁

    ### Hibernate的乐观锁与悲观锁 #### 一、引言 在并发环境下,尤其是在金融、电商等业务场景中,确保数据的一致性和完整性至关重要。**Hibernate**作为一种流行的Java持久层框架,提供了多种机制来处理并发控制...

    面试必备之乐观锁与悲观锁

    【描述】:“面试必备之乐观锁与悲观锁.pdf”涉及的是并发控制中的两种重要锁机制——悲观锁和乐观锁,它们是多线程环境下确保数据一致性的重要手段。 【标签】:“求职面试 多线程” 【正文】: 悲观锁和乐观锁...

    面试必备之乐观锁与悲观锁.zip

    乐观锁和悲观锁是数据库事务控制...了解和掌握乐观锁与悲观锁的原理和应用场景,对于提升面试者的数据库管理技能和解决并发问题的能力至关重要。在面试中,深入探讨这些话题将有助于展示自己的专业水平和问题解决能力。

    数据库乐观锁与悲观锁1

    乐观锁与悲观锁各有优缺点。悲观锁适合于高并发写操作的场景,可以防止丢失更新,但可能导致死锁问题。乐观锁则适用于写操作较少,且可以接受偶尔的冲突重试的情况,它减少了锁的开销,提升了系统的吞吐量。然而,...

    面试必备之乐观锁与悲观锁.docx

    "面试必备之乐观锁与悲观锁" 在多线程编程中,锁机制是必不可少的一部分,锁机制可以防止多个线程同时访问共享资源,避免数据不一致和混乱的情况。锁机制可以分为悲观锁和乐观锁两种,下面我们将详细介绍这两种锁...

    面试资源乐观锁与悲观锁

    面试资源乐观锁与悲观锁

    JAVA架构面试专题_面试必备之乐观锁与悲观锁.pdf

    Java 架构面试中,乐观锁与悲观锁是两个重要的并发控制概念,它们在多线程环境下用于确保数据的一致性。理解这两种锁对于开发者来说至关重要,特别是在高并发的系统设计中。 **悲观锁**是一种保守的并发控制策略,...

    thinkPHP框架乐观锁和悲观锁实例分析

    除了上述的乐观锁和悲观锁实现技巧之外,ThinkPHP框架还提供了其他很多与数据操作和事务管理相关的功能和技巧。例如,在ThinkPHP中,可以使用事务控制相关的类和方法,如mysqli的transaction方法开始事务,commit...

    Hibernate乐观锁和悲观锁分析

    【Hibernate乐观锁与悲观锁详解】 在开发过程中,尤其是在并发环境下,确保数据的一致性和完整性至关重要。Hibernate,作为Java领域广泛使用的ORM框架,提供了一种处理并发数据访问冲突的手段,那就是锁机制。主要...

    面试必备之乐观锁与悲观锁.rar

    1. **事务隔离级别**:乐观锁和悲观锁与数据库的事务隔离级别密切相关。例如,读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和串行化(SERIALIZABLE)这四种隔离级别都会...

Global site tag (gtag.js) - Google Analytics