我有两个 Java 1.7 应用程序使用 Eclipselink 2.4.2 进行持久化。一个应用程序是在 Glassfish 3.1.2.2 中运行的 JEE 应用程序,另一个是 Java SE 应用程序。这些应用程序读取和写入相同的数据,因此可能存在陈旧的 JPA 缓存条目。我正在尝试使用 Oracle DCN解决陈旧的缓存问题。
我已经按照上面的链接配置了我的 persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="drms-persistence-unit" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/DRMS</jta-data-source>
<properties>
<property name="eclipselink.cache.database-event-listener"
value="org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListener"/>
<property name="eclipselink.target-server" value="SunAS9"/>
<property name="eclipselink.target-database" value="Oracle"/>
<property name="eclipselink.logging.level" value="INFO"/>
<property name="eclipselink.logging.parameters" value="true"/>
<property name="eclipselink.jdbc.native-sql" value="true"/>
<property name="eclipselink.jdbc.batch-writing" value="Oracle-JDBC"/>
<property name="eclipselink.jdbc.cache-statements" value="true"/>
<property name="eclipselink.jdbc.cache-statements.size" value="200"/>
</properties>
</persistence-unit>
</persistence>
然而,我仍然得到陈旧的缓存条目。如果一个应用程序提交了对数据库的更改,第二个应用程序仍然会看到其旧的陈旧缓存条目,而不是新的更改。使用调试器,我已经确认 OracleChangeNotificationListener 正在接收数据库事件,但它似乎从未真正使缓存中的任何内容无效。
Eclipselink OracleChangeNotificationListener 注册以下监听器以接收 Oracle 数据库更改事件:
public void onDatabaseChangeNotification(DatabaseChangeEvent changeEvent) {
databaseSession.log(SessionLog.FINEST, SessionLog.CONNECTION, "dcn_change_event", changeEvent);
if (changeEvent.getTableChangeDescription() != null) {
for (TableChangeDescription tableChange : changeEvent.getTableChangeDescription()) {
ClassDescriptor descriptor = OracleChangeNotificationListener.this.descriptorsByTable.get(new DatabaseTable(tableChange.getTableName()));
if (descriptor != null) {
CacheIndex index = descriptor.getCachePolicy().getCacheIndex(fields);
for (RowChangeDescription rowChange : tableChange.getRowChangeDescription()) {
CacheId id = new CacheId(new Object[]{rowChange.getRowid().stringValue()});
CacheKey key = databaseSession.getIdentityMapAccessorInstance().getIdentityMapManager().getCacheKeyByIndex(
index, id, true, descriptor);
if (key != null) {
if ((key.getTransactionId() == null) || !key.getTransactionId().equals(changeEvent.getTransactionId(true))) {
databaseSession.log(SessionLog.FINEST, SessionLog.CONNECTION, "dcn_invalidate", key.getKey(), descriptor.getJavaClass().getName());
key.setInvalidationState(CacheKey.CACHE_KEY_INVALID);
}
}
}
}
}
}
}
每当我们对数据库进行更改时,都会调用此监听器。但是,查找的 CacheKey 值始终为 null,因此无效代码永远不会运行。
如果我在调试器中检查 IdentityMapManager 对象,我可以看到预期的实体在缓存中。然而,CacheId 的查找每次都失败(返回 null)。
感谢任何帮助。
最佳答案
问题已经解决。这是由 persistence.xml 中的“eclipselink.target-database”属性值引起的。我们将它设置为“Oracle”,并将其更改为“Oracle11”解决了这个问题。显然,直到 Oracle 版本 11 才添加 DCN 功能,并且 Eclipselink 的行为因该值而异。
关于java - JPA Eclipselink 数据库更改通知不会使缓存条目无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22149130/