8 Object Locking
8.1 Configuring Default Locking
如何使用lock对load时的性能有重要的影响。OpenJPA通过openjpa.ReadLockLevel和openjpa.WriteLockLevel来配置缺省的事务读写lock level。这些缺省配置只适用于非乐观事务;在乐观事务中,OpenJPA缺省不进行lock。在尝试获取lock时,可以通过openjpa.LockTimeout配置最长的等待时间(缺省值-1指定没有限制),超过这个时间后OpenJPA会抛出异常。配置方式如下:
Xml代码
<property name="openjpa.ReadLockLevel" value="none"/>
<property name="openjpa.WriteLockLevel" value="write"/>
<property name="openjpa.LockTimeout" value="30000"/>
<property name="openjpa.ReadLockLevel" value="none"/>
<property name="openjpa.WriteLockLevel" value="write"/>
<property name="openjpa.LockTimeout" value="30000"/>
8.2 Configuring Lock Levels at Runtime
在每个事务开始时,OpenJPA初始化EntityManager的缺省lock levels和time out。在运行时可以通过EntityManager的FetchPlan 接口修改这些配置。也可以通过Query相关的fetch plan修改Query级别上的配置。这些运行时的修改可以在乐观事务中使用,但是不能在事务之外进行锁定。以下是个简单的例子:
Java代码
// load stock we know we're going to update at write lock mode
em.getTransaction().begin();
Query q = em.createQuery("select s from Stock s where symbol = :s");
q.setParameter("s", symbol);
OpenJPAQuery oq = OpenJPAPersistence.cast(q);
FetchPlan fetch = oq.getFetchPlan ();
fetch.setReadLockMode(LockModeType.WRITE);
fetch.setLockTimeout(3000); // 3 seconds
Stock stock = (Stock) q.getSingleResult();
// load an object we don't need locked at none lock mode
fetch = OpenJPAPersistence.cast(em).getFetchPlan();
fetch.setReadLockMode(null);
Market market = em.find(Market.class, marketId);
stock.setPrice(market.calculatePrice(stock));
em.getTransaction().commit();
// load stock we know we're going to update at write lock mode
em.getTransaction().begin();
Query q = em.createQuery("select s from Stock s where symbol = :s");
q.setParameter("s", symbol);
OpenJPAQuery oq = OpenJPAPersistence.cast(q);
FetchPlan fetch = oq.getFetchPlan ();
fetch.setReadLockMode(LockModeType.WRITE);
fetch.setLockTimeout(3000); // 3 seconds
Stock stock = (Stock) q.getSingleResult();
// load an object we don't need locked at none lock mode
fetch = OpenJPAPersistence.cast(em).getFetchPlan();
fetch.setReadLockMode(null);
Market market = em.find(Market.class, marketId);
stock.setPrice(market.calculatePrice(stock));
em.getTransaction().commit();
8.3 Lock Manager
OpenJPA 内部使用org.apache.openjpa.kernel.LockManager 处理locking相关的实际工作。可以通过openjpa.LockManager 属性进行配置,它有以下选项。
8.3.1 pessimistic
这个选项是org.apache.openjpa.jdbc.kernel.PessimisticLockManager 的一个别名。它使用SELECT FOR UPDATE (或其它等效的)语句锁定跟entity实例对应的数据库行,并且不区分read locks和write locks,也就是说所有的locks都是write locks。例如:
Xml代码
<property name="openjpa.LockManager" value="pessimistic(VersionCheckOnReadLock=true,VersionUpdateOnWriteLock=true)"/>
<property name="openjpa.LockManager" value="pessimistic(VersionCheckOnReadLock=true,VersionUpdateOnWriteLock=true)"/>
8.3.2 none
这个选项是org.apache.openjpa.kernel.NoneLockManager的一个别名。它不进行任何锁定。例如:
Xml代码
<property name="openjpa.LockManager" value="none"/>
<property name="openjpa.LockManager" value="none"/>
8.3.3 version
这个选项是org.apache.openjpa.kernel.VersionLockManager的一个别名。它不进行排他锁定;相反,在事务结束时,它通过校验version来确保被read locks锁定的对象的一致性。无论被write locks锁定的对象是否被修改,其version都会被累加。为了避免脏读,事务的隔离级别应该至少为"read committed"以上。
8.4 Rules for Locking Behavior
OpenJPA的隐含锁定行为有以下规则:
在事务中,当第一次读取某个对象的persistent state的时候,OpenJPA使用fetch plan中当前的read lock level锁定这个对象。未来对这个对象上的lazy persistent state的读取也采用相同的read lock level(无论fetch plan中的lock level是否改变)。
在事务中,当第一次修改某个对象的persistent state的时候,OpenJPA使用该对象第一次被读取时的write lock level(无论fetch plan中的lock level是否改变)。如果对象在之前没有被读取过,那么使用当前的write lock level。
当使用persistent relation field 访问某个对象的时候,这个对象在load过程中被当前fetch plan中的lock level锁定,而不是持有这个field的对象所"记住"的那个lock level。
在事务中,每次访问某个对象的时候,这个对象会被当前的read lock level重新锁定,并且这个read lock level会被该对象"记住"(规则1,2)。
如果显式地通过locking APIs锁定某个对象,那么这些操作都是再次锁定,并且这个lock level会被该对象"记住"(规则1,2)。
如果某个对象已经被锁定,那么尝试使用低级别的lock level再次锁定该对象会被忽略,也就是说在事务中,lock level不能被降低。
8.5 Known Issues and Limitations
出于性能的考虑和数据库的限制等,locking有以下限制:
在乐观事务中,OpenJPA通常会直到flush或commit前才真正开始事务。当使用pessimistic lock manager时,OpenJPA必须在乐观事务中锁定某个对象时开始事务。这因为pessimistic lock manager需要使用数据库的lock。此时OpenJPA会以INFO级别在openjpa.Runtime category中输出一条日志。
出于性能的考虑,OpenJPA只保证在从datastore中得到了某个对象的persistent state之后才进行锁定。这意味这其它事务可能在锁定前修改其persistent state。可以通过在锁定后refresh这个对象来确保这个对象被成功锁定。当使用pessimistic lock manager的时候,这个情况只在无法使用SELECT FOR UPDATE(或其它等效的)语句的时候,例如某些数据库不支持SELECT FOR UPDATE中使用join。此时OpenJPA会以INFO级别在openjpa.Runtime category中输出一条日志。
9 Enhancement
OpenJPA使用enhancer来支持运行时性能优化、延迟加载、脏检查等功能。被enhancer修改过的字节码是Java debugger兼容的,而且很好地保留了stack trace中的行号。唯一的需要注意的是,如果采用property access,那么修改后的getter和setter方法名,在stack track中或者step-through时,会加上"pc"前缀。
9.1 Enhancing at Build Time
Enhancer可以在build的时候被调用。如果对已经加强过的class再次进行加强,那么不会对class文件做更多的修改。可以在命令行上通过PCEnhancer类进行加强,例如:
Java代码
java org.apache.openjpa.enhance.PCEnhancer Magazine.java
java org.apache.openjpa.enhance.PCEnhancer Magazine.java 以下是几个可选的命令行参数:
-directory/-d <output directory>: 输出的class文件的路径。
-enforcePropertyRestrictions/-epr <true/t | false/f>: 如果entity使用property access,但是却没有遵守相关限制的时候,是否抛出异常。缺省是false。
-addDefaultConstructor/-adc <true/t | false/f>: JPA规范要求所有的persistence class必须提供一个无参构造函数。这个标志指示enhancer在persistence class没有提供无参构造函数的时候,是否创建一个protected型的无参构造函数。缺省是true。
-tmpClassLoader/-tcl <true/t | false/f>: 是否使用临时classloader加载persistence class。 缺省是true。
9.2 Enhancing on Deployment
在entities被部署到container的时候,Java EE 5 规范包含hooks来自动加强这些entities。 因此,如果使用Java EE 5兼容的应用服务器,OpenJPA会自动在运行时加强entities。如果某些entites使用了build时的enhancement,那么OpenJPA运行时enhancer会识别并略过这些已经加强过的entities。
9.3 Enhancing at Runtime
在类被载入到JVM的时候,可以使用OpenJPA agent来加强被载入的persistence class。OpenJPA agent是在应用的main方法执行之前被调用的classes。OpenJPA agent使用JVM hooks来拦截并加强被载入的包含persistence metadata的类。在每一个被载入的类中查找persistence metadata可能会减慢应用的初始化速度。可以设置persistent class list来指示agent只查找包含在persistent class list中的类。以下是使用OpenJPA agent的几个例子:
Java代码
java -javaagent:/home/dev/openjpa/lib/openjpa.jar com.xyz.Main
java -javaagent:/home/openjpa/lib/openjpa.jar=addDefaultConstructor=false com.xyz.Main
java -javaagent:/home/dev/openjpa/lib/openjpa.jar com.xyz.Main
java -javaagent:/home/openjpa/lib/openjpa.jar=addDefaultConstructor=false com.xyz.Main 可以使用OpenJPA's plugin syntax来为agent传递配置。此外也支持以下的选项:
addDefaultConstructor: 输出的class文件的路径。
enforcePropertyRestrictions: 如果entity使用property access,但是却没有遵守相关限制的时候,是否抛出异常。缺省是false。
scanDevPath: 是否检查classpath来查找persistence class。如果没有指定persistent class list,同时设置这个标志为true,那么OpenJPA会检查每一个被载入到JVM的类。
classLoadEnhancement: 指定是否使用load-time class enhancement。缺省是true。
runtimeRedefinition: 指定是否使用class redefinition。缺省是true。
9.4 Omitting the OpenJPA enhancer
OpenJPA并不要求必须运行enhancer。如果没有运行enhancer,OpenJPA使用以下几种可能的替代方法。
9.4.1 Java 6 class retransformation
如果使用Java 6,那么OpenJPA会自动检测并尝试动态注册ClassTransformer来重定义persistence class。同时OpenJPA也会为persistence class创建子类。当执行query或者遍历关系的时候,OpenJPA会返回子类的对象,因此instanceof操作符仍然会正确工作,但是o.getClass() 会返回子类类型。
9.4.2 Java 5 class redefinition
如果使用Java 5,并指定了OpenJPA agent,那么OpenJPA会使用Java 5 class redefinition 来重定义没有被agent加强的persistence class。由于agent缺省会进行加强,因此这只有在为agent设置classLoadEnhancement 为false的时候有效(或者其它特殊情况)。
9.4.3 State comparison and subclassing
在以上情况外,OpenJPA会创建persistence class的子类。然而在有些情况下,OpenJPA无法在访问psersistence state的时候得到通知。
如果使用property access,那么OpenJPA会为从数据库中查询得到的对象自动创建子类,并返回这个子类作为代理。这个子类中的getter和setter方法中增添了额外的代码以便通知OpenJPA所有对persistence state的访问。对于你自己创建的对象,由于无法使用子类代理,因此会在脏检查的时候使用state比较的方式。在这种方式下要额外保存该对象的一个snap shot以便用于比较。
如果使用field access,那么OpenJPA无法跟踪对psrsistence state的访问。因此OpenJPA会在脏检查的时候使用state比较的方式,代价是性能上的降低和内存使用的增加。此外,single-valued fields (one-to-one, many-to-one, and any other non-collection or non-map field that has a lazy loading configuration)上的延迟加载的相关配置也被忽略,因为OpenJPA无法跟踪最这些field的访问。
分享到:
相关推荐
• Object locking mechanism: safe hardware access to prevent multiple spurious accesses to shared resources. • Timeout used for all blocking processes: the timeout can be a simple counter or a time...
同时,PowerCenter提供了一套完整的安全性框架,包括Repository Privileges、Folder Permissions、Object Locking以及User ID和password管理,确保数据的安全访问和权限控制。 5. 用户管理与权限 用户管理涉及User...
Object Locking Synchronization Support in the Instruction Set Synchronized Statements Synchronized Methods Coordination Support in Class Object On the CD-ROM The Resources Page Appendix A. ...
5. **监控和诊断**:定期检查锁定统计信息,使用`V$SESSION_WAIT`、`V$LOCKED_OBJECT`等动态性能视图来识别和解决问题。 总的来说,《Oracle Locking Survival Guide》是一份全面的参考资料,涵盖了Oracle数据库中...
锁定(Locking)是为了防止在数据库系统中同时进行的多个事务对相同数据进行并发更新,从而避免数据不一致和死锁的情况。SQL Server通过动态管理锁定来实现这一目标,但理解Transact-SQL查询如何影响锁定策略对于...
Analyze the output of blocking scripts and Microsoft® SQL Server™ Profiler to troubleshoot locking and blocking issues. Formulate hypothesis to resolve locking and blocking issues. ...
Command Window addition for batch locking/unlocking of report files: REPORT LOCKFORALL <path> <password> [R] REPORT LOCKFOROTHERS <path> <password> [R] REPORT UNLOCK <path> <password> [R] REPORT LIST ...
* Support for "conversations" - NHibernate supports long-lived persistence contexts, detach/reattach of objects, and takes care of optimistic locking automatically * Free/open source - NHibernate ...
* Support for "conversations" - NHibernate supports long-lived persistence contexts, detach/reattach of objects, and takes care of optimistic locking automatically * Free/open source - NHibernate ...
* Support for "conversations" - NHibernate supports long-lived persistence contexts, detach/reattach of objects, and takes care of optimistic locking automatically * Free/open source - NHibernate ...
Oracle中的锁定主要包括行级锁定(Row-Level Locking)、表级锁定(Table-Level Locking)等不同级别。其中,非升级行级锁定(Non-Escalating Row-Level Locking)是一种常用的锁定方式,它可以在不影响其他用户对...
这种双重检查锁定(Double-Check Locking)策略既保证了线程安全性,也避免了不必要的锁操作,提高了效率。 #### 客户端代码示例 客户端可以通过调用`Singleton.GetInstance()`方法获取单例对象,如下所示: ```...
这个异常通常在乐观锁(Optimistic Locking)机制失败时抛出,意味着在数据库操作过程中,数据的版本信息(version)与预期不符,即在读取和更新之间,数据已被其他事务修改。 乐观锁是一种并发控制策略,它假设在...
This project is based on Java, is a lightweight ORM model. Only concerned about the Object-Relationl Mapping, therefore more ...Support for optimistic locking; A rich set of tools for SQL statements;
3. 双重检查锁定(Double-Check Locking): 这种模式在懒汉式的基础上优化了性能,减少了同步的范围。代码如下: ```csharp public class Singleton { private static volatile Singleton instance; private ...
为解决线程安全问题,可以使用双重检查锁定(Double-Check Locking)或静态内部类实现。 ```java public class Singleton { private static volatile Singleton instance = null; private Singleton() {} ...
双重检查锁定(Double-Check Locking) 这种实现方式结合了懒汉式的延迟初始化和饿汉式的线程安全性。 ```csharp public sealed class Singleton { private static volatile Singleton instance; private ...
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,广泛应用于Web服务和客户端应用中。 结合以上分析,我们可以探讨以下几个IT知识领域: 1. **数据...
3. **双检锁/双重校验锁(DCL,Double-Checked Locking)**:结合了懒汉式和饿汉式的优点,既延迟初始化又保证了线程安全,但实现起来较为复杂。 ```csharp public sealed class Singleton { private static ...