2014-03-03 61 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的行爲依賴於該值。