【问题标题】:Wildfly failed to start when Hibernate query cache is active当 Hibernate 查询缓存处于活动状态时,Wildfly 无法启动
【发布时间】:2019-11-15 07:41:49
【问题描述】:

我们正在将我们的应用程序从 JBoss EAP 6.4 迁移到 WildFly 14。我们遇到了 Hibernate 和 Infinispan 的问题。

应用程序配置为使用 Hibernate 的二级缓存(也称为 2LC)和 Wildfly 提供的 Infinispan。

启用 2LC 缓存但禁用查询缓存后,应用程序启动并且似乎正常工作。

但是当我们尝试再次启用查询缓存(属性 hibernate.cache.use_query_cache 设置为 true)时,它会在初始化期间崩溃,并给出连接的堆栈跟踪。

java.lang.ClassCastException: org.infinispan.hibernate.cache.v53.impl.DomainDataRegionImpl cannot be cast to org.hibernate.cache.spi.QueryResultsRegion

在调试时,我不明白为什么管理二级缓存的Hibernate内部代码试图将实体缓存区域转换为查询结果缓存区域。

我尝试使用单独的缓存,通过定义属性 hibernate.cache.infinispan.query.cfg 与缓存 local-query 在Infinispan 配置,但是 Hibernate 似乎没有考虑到它。

我是缓存的初学者,我必须承认我并不完全理解我在做什么,即使在阅读了很多文档之后。

版本:

  • 休眠 5.3.6.Final
  • Infinispan 9.3.1.Final
  • WildFly 14.0.1.Final
  • OpenJDK 1.8

这里是我们关注的pom.xml中的Maven依赖声明(应用分为几个Maven项目)

  • org.infinispan:infinispan-spring4-embedded(默认/编译)
  • org.infinispan:infinispan-core(提供)
  • org.infinispan:infinispan-commons(提供)
  • org.infinispan:infinispan-hibernate-cache-v53(提供)
  • org.infinispan:infinispan-hibernate-cache-spi(提供)
  • org.infinispan:infinispan-hibernate-cache-commons(提供)

所有这些都在版本 9.3.1.Final

这是存储在 standalone.xml 中的缓存容器配置:

        <subsystem xmlns="urn:jboss:domain:infinispan:7.0">
            ...
            <cache-container name="hibernate" module="org.infinispan.hibernate-cache">
                <local-cache name="entity">
                    <transaction mode="NON_XA"/>
                    <object-memory size="10000"/>
                    <expiration max-idle="100000"/>
                </local-cache>
                <local-cache name="local-query">
                    <object-memory size="10000"/>
                    <expiration max-idle="100000"/>
                </local-cache>
                <local-cache name="timestamps"/>
            </cache-container>
        </subsystem>

我们的 jboss-deployment-structure.xml 的依赖项部分。

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
    <deployment>
        ...
        <dependencies>
            <!-- Infinispan -->
            <module name="org.infinispan" /> 
            <module name="org.infinispan.commons" />
            <module name="org.infinispan.hibernate-cache"/>

        </dependencies>
    </deployment>
</jboss-deployment-structure>

我们的 Infinispan 配置文件:

<infinispan
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:infinispan:config:7.0 http://www.infinispan.org/schemas/infinispan-config-7.0.xsd"
    xmlns="urn:infinispan:config:7.0">
    <threads />

    <cache-container name="DefaultCacheManager"
        statistics="true">
        <transport />
        <jmx duplicate-domains="true" />

        <local-cache name="___defaultcache">
            <transaction mode="NONE" />
        </local-cache>

        <local-cache name="defaultCache">
            <transaction mode="NONE" />
            <expiration lifespan="1000" max-idle="1000" interval="500" />
            <memory>
                <object size="1000" />
            </memory>
            <persistence passivation="false">
                <file-store purge="false" read-only="false"
                    path="${jboss.server.temp.dir}/cacheservice" />
            </persistence>
        </local-cache>

        <local-cache name="local-query">
            <locking isolation="READ_COMMITTED" concurrency-level="1000"
                acquire-timeout="15000" striping="false" />
            <eviction max-entries="140000" strategy="LRU" />
            <expiration max-idle="1200000" />
            <transaction mode="NONE" auto-commit="false" />
        </local-cache>

        <!-- Other application caches ... -->

    </cache-container>
</infinispan>

WildFly 独立实例在尝试装载 2LC 缓存时在初始化期间崩溃,而不是正确启动,并提供以下堆栈跟踪。

hibernate.cache.use_query_cache 设置为 false 可以解决问题,但我们确实需要查询缓存。

Caused by: java.lang.ClassCastException: org.infinispan.hibernate.cache.v53.impl.DomainDataRegionImpl cannot be cast to org.hibernate.cache.spi.QueryResultsRegion
    at org.hibernate.cache.internal.EnabledCaching.makeQueryResultsRegionAccess(EnabledCaching.java:491)
    at org.hibernate.cache.internal.EnabledCaching.getQueryResultsCache(EnabledCaching.java:478)
    at org.hibernate.loader.Loader.listUsingQueryCache(Loader.java:2515)
    at org.hibernate.loader.Loader.list(Loader.java:2498)
    at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1959)
    at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:370)
    at fr.bdf.interop.middle.dao.hibernate.HibernateGenericDao.find(HibernateGenericDao.java:110)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
    at com.sun.proxy.$Proxy204.find(Unknown Source)
    ...

谢谢,

【问题讨论】:

  • 发生这种情况是因为您已经创建了应该保存与您请求保存查询数据的区域同名的实体/集合的区域。您是否为任何实体或任何查询设置区域名称?如果你正在调试这个,regionName 是什么?也发布你的 persistence.xml。
  • 问题是我找不到代码定义哪个区域保存实体/集合或查询的位置。
  • 持久化没有定义任何区域名称。调试时,我在 makeQueryResultsRegionAccess() 方法中看到与实体相关的区域名称。

标签: java hibernate wildfly infinispan second-level-cache


【解决方案1】:

我终于找到了解决方法。正如 Radim Vansa 所说,问题来自实体/集合缓存区域和查询缓存区域之间的冲突。

在与缓存相关的 Hibernate 文档中,我发现要为 Query 或 Criteria 定义缓存区域名称,必须使用 setCacheRegion(String) 方法。

通过在我们的代码中搜索所有这些方法调用,我终于意识到在我们抽象的通用 DAO 类中,我们这样定义查询区域名称:

public HibernateGenericDao(Class<E> type) {
    ...
    this.cacheRegion = type.getCanonicalName();
}

然后在这里使用 cacheRegion 字段:

criteria.setCacheRegion(getCacheRegion());

鉴于实体/集合缓存区域名称也是由实体类完全限定名称定义的(我们不知道如何),在查询缓存区域名称后添加后缀解决冲突并使应用程序正确启动。

this.cacheRegion = type.getCanonicalName().concat(QUERY_CACHE_REGION_PREFIX);

谢谢,

【讨论】:

    【解决方案2】:

    我在迁移到 WildFly 17.0.0.Final 后遇到了同样的问题。应用程序服务器的模块文件夹中已经包含 Hibernate 5.3.10。在调查了这个问题后,我发现实际上 Hibernate 版本有 https://hibernate.atlassian.net/browse/HHH-13586 错误。由于我没有任何将我们的项目从 WildFly 17 迁移到更新版本的计划,我决定修补当前版本的 Hibernate 库。所以我刚刚下载了 5.3.10 版本并通过 https://github.com/hibernate/hibernate-orm/commit/2076c68ddff5dc39055e90e162a34c99c72261cb 提交修补了 hibernate-core 模块,构建它并更改了 WildFly 模块文件夹中的原始 hibernate-core 库。 java.lang.ClassCastException 消失了。也许它会帮助别人。

    【讨论】:

      猜你喜欢
      • 2015-03-28
      • 2014-09-18
      • 2011-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多