对 JPA 应用程序进行故障诊断
使用此信息来找出 Java™ Persistence API (JPA) 应用程序的各种已知问题。
过程
- 对使用 JPA 瘦客户机 JAR 时 org.apache.openjpa.* 或 com.ibm.websphere.persistence.*
类的 NoClassDefFoundError 进行故障诊断。
在 WebSphere® Application Server V9.0 中,提供了两个 JPA 瘦客户机 JAR 文件。com.ibm.ws.jpa-2.1.thinclient_9.0.jar:包含 JPA 2.1 规范接口以及 EclipseLink 类和接口。com.ibm.ws.jpa-2.0.thinclient_9.0.jar:包含 JPA 2.0 规范接口以及 WSJPA 和 OpenJPA 类和接口。在 V9 以前,这个 JAR 名为 com.ibm.ws.jpa_X.X.jar。
避免故障:
如果您的应用程序依赖于 OpenJPA 或 WSJPA 特定的类或行为,并且您已将 com.ibm.ws.jpa-2.1.thinclient_9.0.jar 添加到类路径,那么应改为在瘦客户机类路径中使用 com.ibm.ws.jpa-2.0.thinclient_9.0.jar。
gotcha - 对 WebSphere Application Server 上运行的应用程序中 org.apache.openjpa.* 或 com.ibm.websphere.persistence.* 类的 NoClassDefFoundError 进行故障诊断。 在 WebSphere Application Server V9.0 中,新概要文件的缺省持久性提供程序已从 OpenJPA 更改为 EclipseLink。如果在 WebSphere 配置为使用 EclipseLink 时运行 OpenJPA 应用程序,那么将会导致 NoClassDefFoundError,因为在服务器运行时配置为使用 JPA 2.1 时,OpenJPA 类不可用。注: 如果使用 WebSphere Application Server V8.5.5 迁移工具来迁移到 WebSphere Application Server V9.0,那么 JPA 级别将自动设置为 2.0,这将使用与 WebSphere Application Server V8.5.5 相同的 JPA 提供程序。
要解决此问题,请将服务器或集群重新配置为使用 JPA 2.0。这会将 OpenJPA 设置为缺省持久性提供程序。
- 对 NoClassDefFoundError 进行故障诊断:org.apache.openjpa.enhance.PersistenceCapable。使用
OpenJPA 的应用程序可以对实体类运行构建时增强工具。使用 OpenJPA 增强功能还会向编译的类添加对 org.apache.openjpa.enhance.PersistenceCapable 等类的引用。 在 WebSphere Application Server V9.0 中,新概要文件的缺省持久性提供程序已从 OpenJPA 更改为 EclipseLink。如果在 WebSphere Application Server 配置为使用 EclipseLink 时您尝试运行 OpenJPA 增强应用程序,那么将会导致 NoClassDefFoundError,因为在服务器运行时配置为使用 JPA 2.1 时,OpenJPA 类不可用。注: 如果使用 WebSphere Application Server V8.5.5 迁移工具来迁移到 WebSphere Application Server V9.0,那么 JPA 级别将自动设置为 2.0,这将使用与 WebSphere Application Server V8.5.5 相同的 JPA 提供程序。要解决此问题,您可以:
- 将服务器或集群重新配置为使用 JPA 2.0。这会将 OpenJPA 设置为缺省持久性提供程序。
- 重新编译应用程序,并使用 EclipseLink 增强功能(而不是 OpenJPA 增强功能)来增强实体。
- 查看与事务相关的消息。
在特定情况下,可能会记录类似如下的消息:无法对 WebSphere 管理的事务执行 {0}。WebSphere 不支持直接处理受管事务。
导致此错误的原因可能是未将数据源正确地配置为 <non-jta-data-source>。请参阅信息中心主题“关联持久性提供程序和数据源”,以了解如何将要使用的数据源配置为 <non-jta-data-source>。
- 对运行时尚未增强的类进行故障诊断。
这些情况难以诊断。有时,问题可追溯到缺乏实体类的 OpenJPA 增强这一情况。这些情况的示例可能会检测到实体无法持久这一情况。在日志中查找类似如下的消息:此配置不允许运行时优化,但系统在构建时或类装入时未使用 Java 代理增强下面列示的类型:“{0}”。
此消息指示所列出的实体类型上未执行预期的运行时增强。在大多数情况下,此错误只是构建时故障,并且必须对列示的类运行 PCEnhancer。它也可能指示一个更为棘手的问题,尤其是在您希望容器类装入器变换执行实体增强的情况下。
- 对关闭游标问题进行故障诊断。 以下是日志 org.apache.openjpa.persistence.PersistenceException 中的 DB2® 异常:
[ibm][db2][jcc][10120][10898] Invalid operation: result set is closed can be a WebSphere Application Server configuration problem.
缺省情况下,应用程序服务器将 resultSetHoldability 定制属性值配置为 2 (CLOSE_CURSORS_AT_COMMIT)。此属性将导致 DB2 在事务边界关闭其结果集/游标。尽管 DB2 的缺省 resultSetHoldability 值为 1 (HOLD_CURSORS_OVER_COMMIT),但应用程序服务器将缺省值保留为 2 以避免中断与前发行版应用程序服务器的兼容性。可更改缺省值。注意: 如果此数据源是 XA 数据源,请对此数据源定义新定制属性,其中 property_name = downgradeHoldCursorsUnderXa,boolean value = true。避免故障: 在 V8.0 中,如果使用 DB2 XA 数据源,那么需要进行下列配置以解决结果集已关闭问题:
- 使用 DB2 V9.1 FP4(对于 APAR IZ18072)或更高版本。
- 添加定制属性 name="downgradeHoldCursorsUnderXa"、value="true" 和 type="java.lang.Boolean"
- 添加定制属性 name="resultSetHoldability"、value="1" 和 type="java.lang.Integer"
- 避免使用多线程 EntityManager。 如果出现具有以下消息文本的异常,那么您可能无意中支持跨多个线程使用 EntityManager。根据 JPA 规范,EntityManager 仅供单个线程使用。您可能会接收到一条类似如下消息的异常消息(在此上下文中,代理和 EntityManager 本质上相同):可用某些方法解决此问题:
多个并行线程尝试访问单个代理。缺省情况下,代理不是线程安全的;如果您需要并希望代理由多个线程访问,请将 openjpa.Multithreaded property 设置为 true 以覆盖缺省行为。
最佳实践: 使用应用程序管理的(扩展的)持久性上下文时,请利用“获取-使用-结束”模式。在退出使用 EntityManager 的方法前,记住关闭该 EntityManager。使 EntityManager 处于打开状态可能会无意中导致其他线程同时使用同一 EntityManager 实例并可能消耗系统资源。bprac
- 通过 @PersistenceContext 注释来插入 EntityManager 实例,将应用程序更改为使用容器管理的持久性上下文(如果应用程序的编程模型顺应此更改)。本质上,这将通过支持容器进行管理,来强制执行“获取-使用-结束”模式。
- 如此异常文本中所述,快速变通方法是在 openjpa.Multithreaded 属性中配置 OpenJPA 以要求对 EntityManager 进行多线程访问。启用此属性可能会导致不必要的开销。
避免故障: servlet 的实例变量自动由该 servlet 的所有实现共享。对 servlet 实例变量使用 @PersistenceContext 注释可能会无意中导致对同一 EntityManager 进行多线程访问。此外,容器不会清除以此方式插入的任何 EntityManager,直到应用程序停止。对于 servlet,最好选择使用 @PersistenceUnit 注释来插入 EntityManagerFactory。gotcha
- 如果使用乐观锁定,请注意版本情况。在 JPA 体系结构中,持久性提供程序使用 version 属性对持久化实体执行乐观锁定和并行语义;例如:
@Entity public class VersionedTimestampEntity { @Id private int id; @Version private java.sql.Timestamp version; .... }
向数据库中写入实体时,提供程序将 version 属性更新为新值。在执行实体合并操作期间,持久性提供程序将检查此 version 属性以确定要合并的实体是否为该实体的旧副本。如果由于旧版本情况导致操作失败,那么会发生 OptimisticLockException。version 属性可以是下列其中一种类型:- int
- Integer
- short
- Short
- long
- Long
- Timestamp
如果实体已保存并在单独的持久性上下文(该上下文位于平台的精度窗口内)中访存和更新,那么持久性提供程序无法检测到乐观锁定和并行情况。因此,可能不会抛出 OptimisticLockException 并且数据完整性遭破坏。避免故障: 如果对 version 属性使用 Timestamp 类型,那么应用程序必须注意特定的行为(创建 Timestamp 对象时使用的实现精度会显示这一行为)。典型实现使用 System.currentTimeMills 方法。此方法的时间精度是特定于平台的。例如,对于 32 位 Windows,精度为 15 ms,对于 z/OS®,精度为 2 ms。gotcha
- 解决使用实体时的数据库约束违例问题。
WebSphere Application Server 附带的 JPA 提供程序使用约束更新管理器根据每个实体的配置来确定对数据库发出的 SQL 请求的顺序。此更新管理器可以重新安排对数据库发出的 SQL 请求的顺序。这使应用程序不必了解执行其业务逻辑所需的实体管理器操作的顺序,并且能够使用底层批处理支持来优化数据库性能。
由于 JPA 提供程序并不会假定实体之间的关系存在隐式的数据库约束,因此,如果数据库中存在约束(例如,外键约束),那么 JPA 提供程序可能不会按期望的顺序发出 SQL 语句。在这些情况下,可能会发生以下异常或类似的异常:com.ibm.db2.jcc.b.SqlException: DB2 SQL error: SQLCODE: -530, SQLSTATE: 23503, SQLERRMC: xxxxxx
可用某些方法解决此问题:- 通过对持久性单元添加以下配置属性,可以将 OpenJPA 提供程序配置为:在运行时从数据库中读取约束信息并将那些信息应用于更新管理器。
<property name="openjpa.jdbc.SchemaFactory" value="native(ForeignKeys=true)" />
- 应用程序可以将实体增强为,使用 @ForeignKey 注释向 JPA 提供程序指示带有外键约束的关系。
public class Person { @ManyToOne @ForeignKey private Address address; .... }
- 对于 OpenJPA 应用程序,通过对持久性单元添加以下配置属性,可以让应用程序负责对 SQL 语句进行排序。
<property name="openjpa.jdbc.UpdateManager" value="operation-order" />
指定此配置选项后,JPA 提供程序将按请求执行实体操作的顺序来启动 SQL 语句。应用程序必须了解实体之间的任何相互依赖关系。
避免故障: 即使您可能倾向于使用这些属性的组合,也只应使用最适合您的情况的属性。如果您认为不必使用这些属性的组合,那么应注意,同时使用 openjpa.jdbc.UpdateManager 和 openjpa.jdbc.SchemaFactory 属性可能不会产生修正该异常所需的 SQL 请求排序。openjpa.jdbc.UpdateManager 属性的 operation-order 设置向 JPA 提供程序指示您希望按在应用程序内指定 SQL 请求的顺序执行 SQL 请求。即使您指定 openjpa.jdbc.SchemaFactory 属性和 openjpa.jdbc.UpdateManager 命令,JPA 提供程序也会遵循应用程序中指定的 SQL 请求顺序而不是自动对 SQL 请求排序以遵循检测到的约束,例如,外键约束。每当指定 openjpa.jdbc.UpdateManager 属性时,由应用程序开发者负责确保在应用程序内以正确顺序指定了 SQL 请求。gotcha
- 从数据库中移除约束。
- 通过对持久性单元添加以下配置属性,可以将 OpenJPA 提供程序配置为:在运行时从数据库中读取约束信息并将那些信息应用于更新管理器。
- 使用 OpenJPA MappingTool ANT 任务进行故障诊断。
OpenJPA 提供的 MappingTool ANT 任务使用临时类装入器来装入 JDBC 驱动程序类。这个临时的类装入器在装入某些 JDBC 驱动程序(例如,DB2)时可能会遇到问题。
运行 MappingTool ANT 任务时,您可能会看到类似于以下的错误:
[mappingtool] java.lang.UnsatisfiedLinkError: com/ibm/jvm/Trace.initTrace([Ljava/lang/String;[Ljava/lang/String;)V [mappingtool] at com.ibm.jvm.Trace.initializeTrace(Trace.java:94) [mappingtool] at com.ibm.jvm.Trace.<clinit>(Trace.java:59) [mappingtool] at java.lang.J9VMInternals.initializeImpl(Native Method) [mappingtool] at java.lang.J9VMInternals.initialize(J9VMInternals.java:200) [mappingtool] at java.lang.Class.forNameImpl(Native Method) [mappingtool] at java.lang.Class.forName(Class.java:136) [mappingtool] at com.ibm.db2.jcc.a.o.n(o.java:577) [mappingtool] at com.ibm.db2.jcc.a.o.<clinit>(o.java:329)要使用映射工具,可以通过对 ANT 任务添加 tmpClassLoader=false 参数来禁用临时类装入器。下面是两个 ANT 脚本示例:
以下示例将展示以下问题:
<taskdef name="mapping" classname="org.apache.openjpa.jdbc.ant.MappingToolTask" classpathref="jpa.cp"/> . . . <target name="map.broken"> <mapping> <!-- this exhibits the problem --> . . . </mapping> </target>
以下示例将阻止以下问题:
<taskdef name="mapping" classname="org.apache.openjpa.jdbc.ant.MappingToolTask" classpathref="jpa.cp"/> . . . <target name="map.fixed"> <mapping tmpClassLoader="false"> <!-- this will work --> . . . </mapping> </target>
- DataCache 对不一致域模型的影响
如果应用程序保留不一致的域模型并且以后在单独的持久性上下文中检索实体,那么根据 DataCache 是否处于活动状态,检索到的实体将有所不同。
例如,假定数据库中的单一外键列所映射的两个实体之间存在双向一对一关系。应用程序可能会不一致地设置这些实体中的关系字段。这样的不一致值映射到数据库时,数据库记录将仅仅因为单一外键列指出双向关系 DataCache 处于活动状态而变为一致,但是,DataCache 接着将捕获到不一致的内存实体状态。因此,如果应用程序保留一对通过双向关系相关但其关系字段设置为不一致值的实体,并且以后在另一持久性上下文中检索那些实体,那么双向关系将保持不一致或者变为一致,这取决于是否使用了 DataCache。
保留不一致的实体状态但在另一持久性上下文中检索到一致状态的另一个示例是,多个字段映射到同一列但设置为不同的值。在这种情况下,DataCache 的引入还将导致在另一持久性上下文中实现实体以便保留不同且不一致的值,而没有 DataCache 时,实体的这两个字段将存放同一个值。
最佳实践: 避免不一致地填充应用程序域模型。对于 OpenJPA,您还可以配置 openjpa.InverseManager 属性以便检测某些不一致情况,例如,双向关系。bprac
- 诊断与 Sybase 相关的 MappingTool 和 @ForeignKey 注释问题。
将 OpenJPA 映射工具与 Sybase Adaptive Server 配合使用时,此工具无法创建 ForeignKey 约束。因此,必须手动地创建外键约束。
- 诊断 DB2 Optim™ pureQuery Runtime 配置选项。 如果要将 DB2 Optim pureQuery Runtime 与 WebSphere Application Server JPA (WSJPA) 提供程序配合使用,那么必须在 persistence.xml 文件中设置以下属性:
<property name="openjpa.Compatibility" value="StrictIdentityValues=true"/>
如果必须设置另一兼容性选项(例如,ReloadOnDetach=false),那么必须在 persistence.xml 文件中将两个选项指定为同一属性语句的参数。例如:
<property name="openjpa.Compatibility" value="StrictIdentityValues=true,ReloadOnDetach=false"/>
避免故障: OpenJPA 兼容性属性不会移除 OpenJPA 为某些数据类型生成的代理类型,特别是日期类型,例如,GregorianCalendar。此省略可能导致反序列化问题。如果发生反序列化问题,那么系统会发出类似如下的错误消息:gotcha
Error Message is:org.codehaus.jackson.map.JsonMappingException: Can not construct instance of org.apache.openjpa.util.java$util$GregorianCalendar$proxy, problem: no suitable creator method found at [Source: org.apache.http.conn.EofSensorInputStream@d83fbd5; line: 1, column: 4094]
- 诊断使用运行 DB2 for z/OS 的数据库时实体中与时间相关的类型属性的问题。 如果实体具有与时间相关的类型属性,并且以数据库为目标的对应映射列不兼容,那么某些情况下可能会出现以下异常:
在下列情况下,您可能会见到此异常:org.apache.openjpa.lib.jdbc.ReportingSQLException: THE DATE, TIME, OR TIMESTAMP VALUE 1 IS INVALID. SQLCODE=-18x, SQLSTATE=22007
- 数据库正在运行 DB2 for z/OS。
- 正在使用指定查询并使用本机 SQL 访问该数据库。
- 本机查询使用与时间相关的字段作为 SQL 参数,但查询与数据库表的列定义不兼容。有关兼容性的更多信息,请参阅 DB2 9.7 信息中心中的受支持的数据转换主题。
子主题
使用 JPA 记录应用程序
记录支持对应用程序的运行时行为进行查看、跟踪和故障诊断。Java™ Persistence API (JPA) 提供了一个灵活记录系统,与应用程序服务器集成以帮助您进行问题故障诊断。对 JPA 死锁和事务超时进行故障诊断
数据库死锁和事务超时是尝试访问同一数据库资源的两个或更多客户机之间争用的结果。死锁是一种特殊情况:两个或更多客户机之间发生循环阻塞条件,每个客户机被另一客户机阻塞,但是没有任何客户机可以继续。通常,这些现象不是编程错误。它们是由以复杂和相互依靠的方式访问数据库资源的业务逻辑造成的。使用 JPA 记录应用程序
记录支持对应用程序的运行时行为进行查看、跟踪和故障诊断。Java™ Persistence API (JPA) 提供了一个灵活记录系统,与应用程序服务器集成以帮助您进行问题故障诊断。对 JPA 死锁和事务超时进行故障诊断
数据库死锁和事务超时是尝试访问同一数据库资源的两个或更多客户机之间争用的结果。死锁是一种特殊情况:两个或更多客户机之间发生循环阻塞条件,每个客户机被另一客户机阻塞,但是没有任何客户机可以继续。通常,这些现象不是编程错误。它们是由以复杂和相互依靠的方式访问数据库资源的业务逻辑造成的。


http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tejb_jpatroubleshoot
文件名:tejb_jpatroubleshoot.html