2014-03-03 31 views
2

我有两个使用Eclipselink 2.4.2的Java 1.7应用程序用于持久性。一个应用程序是在Glassfish 3.1.2.2中运行的JEE应用程序,另一个是Java SE应用程序。这些应用程序读取和写入相同的数据,因此存在陈旧的JPA高速缓存条目的可能性。我试图用Oracle DCN来解决陈旧的缓存问题。JPA Eclipselink数据库更改通知不会使缓存项无效

如上面的链接描述我已经配置我的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值始终为空,因此失效代码永远不会运行。

如果我检查调试器中的IdentityMapManager对象,我可以看到预期的实体在缓存中。然而,CacheId查找每次都失败(返回null)。

任何帮助表示赞赏。

+0

您能否提供更多信息,例如您如何验证实体过时?失效适用于二级缓存,但不适用于EntityManager缓存,因为它与工作单元相似。例如,如果保留和重用EM,请确保在逻辑点呼叫清除 – Chris

+0

我在一个应用程序中对实体进行更改,并验证它是否已提交到数据库。然后我在其他应用程序中检索同一个实体。第二个应用程序实际上并未命中数据库,显示的数据是实体的旧的更新前值。 – Jeff

回答

6

问题已解决。它是由persistence.xml中的“eclipselink.target-database”属性的值引起的。我们将它设置为“Oracle”,并将其更改为“Oracle11”解决了此问题。显然直到Oracle版本11才添加DCN功能,并且Eclipselink的行为依赖于该值。