JPA提供了基于POJO的持久化模型,主要处理数据跟Java对象间的映射,而且也标准化了这种映射。JPA2.0规范中增加了两个主要的特性:OR映射的查询功能及锁的支持。
锁机制跟并发
锁是一种在技术上实现数据库事务的并发控制,当两个或多个数事务并发访问同一个数据时,锁就可以保证在同一时刻只有一个事务可以访问修改此数据。
有两种类型的锁:乐观锁跟悲观锁。乐观锁就是在多个并发事务之间并不会引起冲突,就是说并不会有两个事务同时去读和写同一个数据。所以这种锁会提供很大的自由去操作java对象,但是如果有两个事务同时操作一个数据时就会产生冲突,故我们要有一种检查来避免这种冲突。
悲观锁就是在事务间会经常发生冲突,这种锁是在读取数据的时候就已经把数据锁住,其他事务只能等这个数据释放掉锁之后才能访问。
当没有事务间的冲突时乐观锁是最佳选择,反之则悲观锁是最佳选择。
使用JPA可以在实体上使用锁,这样你就可以控制住何时,何地使用什么类型的锁。一个实体就是一个轻量级的持久化域对象,一个实体对应一个数据库表,而一个实体的实例就代表表中的一条记录。
JPA1.0规范锁的支持
JPA1.0只支持乐观读跟乐观写两种类型的锁,任何事物都可以读写实体对象。当一个事务提交时,JPA会检查实体的属性值Version的值是否被修改过,如果这个值已经被修改过,那么JPA会抛出例外。好处就是数据库不需要任何锁,这样要比悲观锁更灵活,但缺点是用户或者应用程序一旦失败后必须刷新。
在实体上标注@Version即可:
public class User {
@ID int id;
@Version int version;
对应的数据库sql:
CREATE TABLE USER
(ID NUMBER NOT NULL, VERSION NUMBER),
PRIMARY KEY (ID));
属性 version 的类型可以是:int、short、long或者是timesamp。
翻译成sql:
UPDATE User SET ..., version = version + 1
WHERE id = ? AND version = readVersion
附图img0.jpg很详细的解释了乐观锁的机制。
当两个并发事务同时修改对象Part p时,事务1首先提交,p属性version的值会自动加1。当事务2提交时就会抛出例外OptimisticLockException。因为事务2里p对象的version的值要小于当前数据库里version的值,所以事务2就会回滚事务。
你还可以通过指定锁的模式来控制实体。EntityManager
类里的方法logc().就可以实现:
public void lock(Object entity, LockModeType lockMode);
参数1是实体对象,参数2是锁模式。
JPA1.0支持的模式:
READ:事务中提交之前给实体加锁,比较当前实体的version值与数据库中的值是否一致,如果不一致即数据库中version的值大于当前实体的version的值,那么就抛出例外:OptimisticLockException
并回滚事务。
WRITE:操作同READ,唯一不同是无论事务是否成功提交都要将version值加1.
JPA2.0中事务类型:
乐观锁:
OPTIMISTIC:同READ
OPTIMISTIC_FORCE_INCREMENT:同WRITE
悲观锁:
PESSIMISTIC_READ:当一个事务读取一个实体时就给其加锁,直到这个事务完成才将锁释放。通常在不允许重复读的情况下使用该锁。换句话说就是在读时不允许修改此记录。在此锁模式下可以运行其他事务读记录。
PESSIMISTIC_WRITE:在修改一个实体对象时加锁,当多个事务试图修改记录时会强制序列化,通常在并发修改失败
时会用到该锁模式。
PESSIMISTIC_FORCE_INCREMENT
:当事务读取实体时就给其加锁,当事务结束时都要将version值加1.
JPA2.0也提供了多种方式给一个实体加锁。你可以在lock() 跟 find() 方法里指定锁模式。
此外如果你调用EntityManager.refresh()的方法,就会同步当前实体对象跟数据库对象的状态。
你也可以使用setLockMode()方法给查询设置锁。
在JPA2.0里使用锁的例子。
OPTIMISTIC
锁的典型应用是一个实体直接引用到其他的实体对象。
如附件img1.jpg所示的,事务1更改了part对象p1的价格,同时把p1的version的值加1.事务2提交一个User对象u1的bid对象,如果对象part的price值小于当前user对象bid的值,那么事务2就增加bid的值。
在这种情况下,当事务2读取了price值之后,被事务1修改了,那么我们是不希望事务2提交的。这种情况下OPTIMISTIC
是最好的选择。
em.lock(p1, OPTIMISTIC);
然后事务2调用em.flush();这会增加p1对象的version值,任何并发访问p1的事务都会失败,抛出
OptimisticLockException
例外且回滚事务。如图示,当事务2执行em.flush()后,事务1尝试去修改p1对象的price值,当事务1提交时,会检查version的值,因为version的值已经被事务2修改,所以事务1在提交事务时会抛出OptimisticLockException
例外。
悲观锁模式:
当数据库的一行记录被读取后就会将此记录加锁,就相当于执行sql:SELECT . . . FOR UPDATE [NOWAIT]
.悲观锁能够保证事务不会再同一时刻修改同一记录,这可以简化代码,但是却限制了数据的读取,很可能会引起死锁的问题。如果并发发生情况很多时使用悲观锁是比较好的选择。
附件img3.jpg是 PESSIMISTIC_READ锁的示例。
附件img4.jpg是 PESSIMISTIC_WRITE锁的示例。
附件img5.jpg是 PESSIMISTIC_WRITE锁的示例。
- 大小: 53 KB
- 大小: 45.7 KB
- 大小: 46.6 KB
- 大小: 29.1 KB
- 大小: 27.6 KB
- 大小: 24.6 KB
分享到:
相关推荐
- **并发、对象与行锁定**(Concurrency, Objects, and Row Locking):讨论了在多线程环境中如何有效地管理数据访问。 - **开发语言问题**(Development Language Issues):分析了不同编程语言对持久层设计的影响...
事务和并发控制(Transactions and concurrency control)讨论了如何使用Hibernate处理事务,以及如何处理多用户操作时的并发问题。 JNDI(Java Naming and Directory Interface)部分涉及到如何使用Hibernate通过...
11.3. 乐观并发控制(Optimistic concurrency control) 11.3.1. 应用程序级别的版本检查(Application version checking) 11.3.2. 扩展周期的session和自动版本化 11.3.3. 脱管对象(deatched object)和自动版本化 ...
8. 事务与并发控制(Transactions and Concurrency Control):关于如何在Hibernate中管理事务和处理并发问题。 9. 连接工厂命名目录(JNDI):介绍了JNDI在Hibernate配置中的作用和使用方法。 10. 锁定(Locking):...
11.3. 乐观并发控制(Optimistic concurrency control) 11.3.1. 应用程序级别的版本检查(Application version checking) 11.3.2. 长生命周期session和自动版本化 11.3.3. 脱管对象(deatched object)和自动版本化 ...
12.3. 乐观并发控制(Optimistic concurrency control) 12.3.1. 应用程序级别的版本检查(Application version checking) 12.3.2. 长生命周期session和自动版本化 12.3.3. 脱管对象(deatched object)和自动版本化 ...
11.3. 乐观并发控制(Optimistic concurrency control) 11.3.1. 应用程序级别的版本检查(Application version checking) 11.3.2. 扩展周期的session和自动版本化 11.3.3. 脱管对象(deatched object)和自动版本化 ...
11.3. 乐观并发控制(Optimistic concurrency control) 11.3.1. 应用程序级别的版本检查(Application version checking) 11.3.2. 扩展周期的session和自动版本化 11.3.3. 脱管对象(deatched object)和自动版本化 ...
11. Transactions And Concurrency 11.1. Session and transaction scopes 11.1.1. Unit of work 11.1.2. Long conversations 11.1.3. Considering object identity 11.1.4. Common issues 11.2. Database ...
11.3. 乐观并发控制(Optimistic concurrency control) 11.3.1. 应用程序级别的版本检查(Application version checking) 11.3.2. 扩展周期的session和自动版本化 11.3.3. 脱管对象(deatched object)和自动版本化 ...
12.3. 乐观并发控制(Optimistic concurrency control) 12.3.1. 应用程序级别的版本检查(Application version checking) 12.3.2. 长生命周期session和自动版本化 12.3.3. 脱管对象(deatched object)和自动版本化 ...
11.3. 乐观并发控制(Optimistic concurrency control) 11.3.1. 应用程序级别的版本检查(Application version checking) 11.3.2. 扩展周期的session和自动版本化 11.3.3. 脱管对象(deatched object)和自动版本化 ...
乐观并发控制(Optimistic concurrency control) 12.3.1. 应用程序级别的版本检查(Application version checking) 12.3.2. 长生命周期session和自动版本化 12.3.3. 脱管对象(deatched object)和自动版本化 ...
11.3. 乐观并发控制(Optimistic concurrency control) 11.3.1. 应用程序级别的版本检查(Application version checking) 11.3.2. 扩展周期的session和自动版本化 11.3.3. 脱管对象(deatched object)和自动版本化 ...
11.3. 乐观并发控制(Optimistic concurrency control) 11.3.1. 应用程序级别的版本检查(Application version checking) 11.3.2. 长生命周期session和自动版本化 11.3.3. 脱管对象(deatched object)和自动版本化 ...
11.3. 乐观并发控制(Optimistic concurrency control) 11.3.1. 应用程序级别的版本检查(Application version checking) 11.3.2. 扩展周期的session和自动版本化 11.3.3. 脱管对象(deatched object)和自动版本化 ...
乐观并发控制(Optimistic concurrency control) 11.3.1. 应用程序级别的版本检查(Application version checking) 11.3.2. 扩展周期的session和自动版本化 11.3.3. 脱管对象(deatched object)和自动版本化 ...