使用 Infinispan 和 JBoss EAP 7.0.6 的 Hibernate L2C 不工作

Hibernate L2C with Infinispan and JBoss EAP 7.0.6 is not working

我有一个带有 Hibernate 5.0.9.Final 的应用程序部署到 JBoss EAP 7.0.6(默认情况下 Infinispan 8.0.1.Final)。必须缓存几个实体,它们用 JPA 的 @Cacheable 和 Hibernate 的 @Cache 注释以提供每个实体的缓存策略。

代码库包含一个简单的测试,该测试在本地检查 Infinispan 运行ning 以及直接访问数据源的测试用例,也就是说,两者之间没有 JBoss EAP,也没有 Arquillian 测试。测试 运行 成功,我可以看到可用时从缓存中获取实体。

现在将应用程序部署到 JBoss EAP 和 运行ning 会导致负面体验。我可以在 Infinispan 缓存实体的日志中看到。我还可以在 JBoss Web 控制台上看到缓存统计信息。当执行应该产生缓存命中计数的查询时,结果没有发生命中计数,而是查询命中了数据源。

更新: 已使用 persistence.xml 中的适当属性启用了 hibernate 和 infinispan 统计信息; L2C 和查询缓存也是如此。区域工厂设置为 JndiInfinispanRegionFactory,如 http://infinispan.org/docs/8.0.x/user_guide/user_guide.html 中所述。此外,所有执行的查询都是 JPQL 查询。据我所知,告诉 Infinispan 和 JBoss AS/7 使用它们的默认配置。

更新 2: JBoss 服务器实际上是 EAP 7.0.6,而不是前面所述的 AS/7。

我们目前无法升级到更新版本的 JBoss EAP(恐怕现在没有 Wildfly)。

顺便说一句,尝试在本地 运行 EhCache 是成功的,但是 运行 在 JBoss EAP 内部由于模块问题导致 CNFE。

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
            xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
   <persistence-unit name="DefaultUnit" transaction-type="JTA">
       <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
       <jta-data-source>java:/MyDataSource</jta-data-source>
       <class>...</class>
       <exclude-unlisted-classes>true</exclude-unlisted-classes>
       <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
       <properties>
           <property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect" />
           <property name="hibernate.show_sql" value="true" />
           <property name="hibernate.connection.datasource" value="java:/MyDataSource"/>
           <property name="hibernate.generate_statistics" value="true" />
           <property name="hibernate.cache.infinispan.statistics" value="true"/>
           <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
           <property name="hibernate.cache.use_second_level_cache" value="true" />
           <property name="hibernate.cache.use_query_cache" value="true" />
           <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.infinispan.JndiInfinispanRegionFactory"/>
           <property name="hibernate.cache.infinispan.cachemanager" value="java:jboss/infinispan/container/hibernate"/>
       </properties>
   </persistence-unit>
</persistence>

standalone.xml 这个块定义了休眠容器

<cache-container name="hibernate" default-cache="local-query" module="org.hibernate.infinispan">
    <local-cache name="entity">
        <transaction mode="FULL_XA"/>
        <eviction strategy="LRU" max-entries="10000"/>
        <expiration max-idle="100000"/>
    </local-cache>
    <local-cache name="local-query">
        <eviction strategy="LRU" max-entries="10000"/>
        <expiration max-idle="100000"/>
    </local-cache>
    <local-cache name="timestamps"/>
</cache-container>

When a query that should result in cache hit counts is executed it turns out no hit counts occur and the query hits the datasource instead.

当你说查询时,你指的是 JPQL 查询还是 Criteria API?

实体查询是通过实体标识符直接获取的。对于查询,您还需要查询缓存,但不清楚您是否需要它。

此外,如果不启用统计,命中计数可以为 0:

  • 与 Hibernate Core 相关的 hibernate.generate_statistics 之一
  • 或者,hibernate.cache.infinispan.statistics,对于 Infinispan

找出发生了什么的一种方法是调试 DefaultLoadEventListener#doLoad 方法:

entity = loadFromSecondLevelCache( event, persister, keyToLoad );

看看为什么不能从 Infinispan 获取它。

更新:

Also, all executed queries are JPQL queries.

您是否启用了查询缓存?

请注意,查询缓存使用单个区域,因此一旦您add/remove/modify属于该table space.

如果您在尝试加速 JPQL 时依赖实体二级缓存而不使用查询缓存,那么它的工作效率甚至会低于没有二级缓存的情况。这是因为 JPQL 无论如何都会执行 SQL 查询,因此您只需丢弃结果并转到缓存以通过实体的 ID 获取实体。如果在缓存中找不到实体,这实际上会变得非常糟糕,这意味着将发出过多的二次查询。

如果您在执行读写事务时尝试卸载主节点,则二级缓存非常有意义。对于只读查询,只需使用数据库复制并将负载分散到多个副本上,这些副本的缓冲池配置为将整个工作集存储在 RAM 中。

我强烈建议避免这种组合:

  • JBoss AS7 非常古老,无法与 Java 8
  • 完全兼容
  • Infinispan 8 需要 Java 8

既然你说你不能升级到 WildFly(11 即将到来!)你落后了将近 4 个主要版本:这是很多缺失的错误修复和改进,但在库的世代中也有显着差异你正在合并。

我建议:

  • 坚持使用 Ehcache
  • 坚持使用应用服务器中包含的旧版本 Hibernate ORM
  • 更新到 WildFly 11 :-)
  • 获得受支持的 JBoss EAP 7.x

对于对 EAP 的商业引用,我深表歉意,但这可能是一个很好的解决方案,具体取决于您为什么不能升级到 WildFly,因为它本质上是将更高版本(尤其是兼容性修复被向后移植)与严格的 API 向后兼容政策。

关于 Ehcache 让您遇到模块问题,我很乐意提供帮助。模块系统很棒,我相信这可能很容易解决,但最好将其作为不同的问题/论坛来处理。

persistence.xml 配置不正确。部署到 EAP 时,这就是所需的全部内容:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
   <persistence-unit name="DefaultUnit" transaction-type="JTA">
       <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
       <jta-data-source>java:/MyDataSource</jta-data-source>
       <class>...</class>
       <exclude-unlisted-classes>true</exclude-unlisted-classes>
       <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
       <properties>
           <property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect" />
           <property name="hibernate.show_sql" value="true" />
           <property name="hibernate.connection.datasource" value="java:/MyDataSource"/>
           <property name="hibernate.generate_statistics" value="true" />
           <property name="hibernate.cache.infinispan.statistics" value="true"/>
           <property name="hibernate.cache.use_second_level_cache" value="true" />
           <property name="hibernate.cache.use_query_cache" value="true" />
       </properties>
   </persistence-unit>
</persistence>

通过定义您自己的区域工厂,您冒着不使用由您检查统计信息的 EAP 管理的实际 Infinispan 实例的风险。

查看 EAP 7 documentation 了解更多信息。