JPA eclipselink OracleChangeNotificationListener 无法从 CacheId 获取 cacheKey

JPA eclipselink OracleChangeNotificationListener cannot get cacheKey from CacheId

我正在尝试使用 eclipselink 2.6 和 Oracle 11.2 以及 ojdbc6 驱动程序实现 oracle DCN。

目前,通过设置,我可以通过我的接收器正确接收 table 更改通知。

我扩展了 org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListener 以修复我在项目中注意到的几个问题。

首先我重写了注册方法以正确解包连接:

OracleConnection connection = null;
        try {

            Connection unwrapConnection = databaseSession.getServerPlatform().unwrapConnection(accessor.getConnection());
            try {
                if (unwrapConnection.isWrapperFor(OracleConnection.class)) {
                    connection = unwrapConnection.unwrap(OracleConnection.class);
                } else {
                    // recover, not an oracle connection
                    connection = (OracleConnection) databaseSession.getServerPlatform().unwrapConnection(accessor.getConnection());
                }
            } catch (SQLException e) {
                e.printStackTrace();
                throw DatabaseException.sqlException(e, databaseSession.getAccessor(), databaseSession, false);
            }

我还存储每个 table 的 object_id (tableNameIdMap),以便从每个通知中正确找到 table。

这是 DatabaseChangeListener 方法:

public void onDatabaseChangeNotification(final DatabaseChangeEvent changeEvent) {
        if (changeEvent.getTableChangeDescription() != null) {
            for (TableChangeDescription tableChange : changeEvent.getTableChangeDescription()) {
                String tableName = this.tableNameIdMap.get(tableChange.getObjectNumber());
                if (tableName != null)
                {
                    ClassDescriptor descriptor = DatabaseChangeNotificationListener.this.descriptorsByTable.get(new DatabaseTable(tableName));
                    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。

方法 getIdentityMapManager().getCacheKeyByIndex(...) 总是 returns null

通过调试,identityMaManager 似乎应该 return 来自 identityMap(weakHashMap)的 cacheKey。存在对应的 rowId,但未 returned.

这是 IdentityMapManager#getCacheKeyByIndex 中的行

CacheKey cacheKey = map.getCacheKey(indexValues, false);

CacheId 的 hashMap 似乎是基于值哈希码的。但是在查看地图时,我应该接收的值由包含 ROWID 的 CacheId 索引。因此,我看不出这应该如何工作...

我尝试使用以下方法实例化 cacheId:

CacheId id = new CacheId(new Object[]{rowChange.getRowid(});

它仍然不起作用,因为 ROWID 的哈希码似乎是对象的哈希码。

所以我被困在这里了。我不明白这在其他地方如何运作。

感谢任何帮助。

仅供参考,这是我的 persistence.xml

的摘录
    <property name="eclipselink.target-database" value="Oracle11" />
    <property name="eclipselink.jdbc.native-sql" value="true" />
    <property name="eclipselink.jdbc.cache-statements" value="true" />
    <property name="eclipselink.query-results-cache" value="true" />
    <property name="eclipselink.cache.shared.default" value="true"/>
    <property name="eclipselink.refresh" value="true" />
    <property name="eclipselink.weaving" value="true"/>
    <property name="eclipselink.cache.database-event-listener" value="com.isel.persistence.database.DatabaseChangeNotificationListener" />

找到答案:

问题与 this question 大致相同。

我确实在 persistence.xml 中正确设置了 eclipselink.target 数据库,但它被 spring 配置覆盖了:

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
    <property name="showSql" value="false" />
    <property name="generateDdl" value="false" />
    <property name="databasePlatform" value="org.eclipse.persistence.platform.database.OraclePlatform" />
</bean>

然后我改为 <property name="databasePlatform" value="org.eclipse.persistence.platform.database.oracle.Oracle11Platform" />

现在,仅供参考,eclipselink 将 rowId 存储为 CacheId 键中的字符串,这是在以下位置完成的:org.eclipse.persistence.platform.database.oracle.Oracle9Platform.getObjectFromResultSet(ResultSet, int, int, AbstractSession)

else if (type == OracleTypes.ROWID) {
  return resultSet.getString(columnNumber);
}