【问题标题】:Hibernate Infinispan 2LC : query cache and entity cache in same cache regionHibernate Infinispan 2LC:查询缓存和实体缓存在同一个缓存区域
【发布时间】:2023-03-24 12:11:01
【问题描述】:

使用 JBoss Cache,可以将entity 缓存和query 缓存存储在同一个缓存区域中,没有任何问题。但是一旦迁移到wildfly 10(以infinispan为2LC),似乎就有问题了。

我已经为实体提供了缓存区域,如下所示。

@Entity     
@Cacheable  
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY, 
     region="regionA")
public class EntityXYZ{

查询缓存为

 entManager.createQuery(
        "....")
    .setHint("org.hibernate.cacheable", true)
    .setHint("org.hibernate.cacheRegion", "regionA").getResultList();

需要注意的是,上面的query 还包含entities,它们本身被声明为cacheable,并且与regionA 具有相同的缓存区域。

现在执行时,出现此错误。我怀疑这是由于冲突,因为它们存储在同一区域中,并且它试图获取返回另一个对象的对象 id。但是有人可以发光吗。真的是这样吗?并解释更多关于错误的信息?

但同样适用于JBoss 5 的 JBoss 缓存。 infinispan 的处理方式是否不同?还是这是Hibernate 问题?

ERROR [org.jboss.as.ejb3.invocation] (default task-8) WFLYEJB0034: EJB Invocation failed on component... javax.ejb.EJBTransactionRolledbackException: Object [id=4] was not of the specified subclass [ com.abc.xyz] : loaded object was of wrong class class  com.abc.yyy
                at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleInCallerTx(CMTTxInterceptor.java:159)
                at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:256)

     [org.hibernate.event.internal.DefaultLoadEventListener] (default task-8) HHH000327: Error performing load command : org.hibernate.WrongClassException: Object [id=4] was not of the specified subclass [com.abc.xyz] : loaded object was of wrong class class com.abc.yyy

更新:

entitymanager 尝试加载具有 @idint 的 2 个此类(在同一共享缓存 2LC 区域中)的不同调用。正如 Flavius 指出的那样,id=4 似乎在 2 个类之间很常见。

将以下配置添加到 persistence.xml 时,出现启动错误。

persistence.xml

<property name="hibernate.cache.keys_factory" value="default" />

错误

 javax.persistence.PersistenceException: [PersistenceUnit: app-entity] Unable to build Hibernate SessionFactory
            at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:179)
            at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:121)
            at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:667)
            at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:193)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at java.lang.Thread.run(Thread.java:745)
            at org.jboss.threads.JBossThread.run(JBossThread.java:320)
    Caused by: javax.persistence.PersistenceException: [PersistenceUnit: app-entity] Unable to build Hibernate SessionFactory
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:954)
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:882)
            at org.jboss.as.jpa.hibernate5.TwoPhaseBootstrapImpl.build(TwoPhaseBootstrapImpl.java:44)
            at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:161)
            ... 7 more
    Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.spi.CacheImplementor]
            at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:264)
            at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:228)
            at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:207)
            at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:242)
            at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444)
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879)
            ... 9 more
    Caused by: org.hibernate.boot.registry.selector.spi.StrategySelectionException: Unable to resolve name [default] as strategy [org.hibernate.cache.spi.CacheKeysFactory]
            at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.selectStrategyImplementor(StrategySelectorImpl.java:113)
            at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveDefaultableStrategy(StrategySelectorImpl.java:162)
            at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveDefaultableStrategy(StrategySelectorImpl.java:126)

更新 2

我已将default 更改为精确的FQN,但它不起作用。错误不正确,因为该类是指定类的实现。

<property name="hibernate.cache.keys_factory" value="org.hibernate.cache.internal.DefaultCacheKeysFactory" />

错误:

Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.spi.CacheImplementor]
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:264)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:228)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:207)
        at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:242)
        at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879)
        ... 9 more
Caused by: java.lang.ClassCastException: org.hibernate.cache.internal.DefaultCacheKeysFactory cannot be cast to org.hibernate.cache.spi.CacheKeysFactory
        at org.hibernate.cache.infinispan.InfinispanRegionFactory.determineCacheKeysFactory(InfinispanRegionFactory.java:427)
        at org.hibernate.cache.infinispan.InfinispanRegionFactory.start(InfinispanRegionFactory.java:378)
        at org.hibernate.internal.CacheImpl.<init>(CacheImpl.java:49)
        at org.hibernate.engine.spi.CacheInitiator.initiateService(CacheInitiator.java:28)
        at org.hibernate.engine.spi.CacheInitiator.initiateService(CacheInitiator.java:20)
        at org.hibernate.service.internal.SessionFactoryServiceRegistryImpl.initiateService(SessionFactoryServiceRegistryImpl.java:46)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:254)

【问题讨论】:

  • 根据 JIRA 的说法,DefaultCacheKeysFactory 的问题似乎已在 5.0.12、5.1.3 和 5.2.5 中得到修复。通常你应该能够手动将 WF 的 hibernate-orm 模块更新到 5.0.12(对于任何微版本)。
  • 谢谢。如果由于共享缓存区域没有性能提升,那么我将坚持最佳实践。

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


【解决方案1】:

查询缓存是字符串索引的,实体缓存是使用原始ID(与EntityXYZ中用@Id标记的字段/方法相同的对象)索引的,所以我想知道id=4上的冲突是如何发生的。

无论如何,对实体和查询使用相同的区域(缓存)并不是一个好主意 - 实体有时需要更复杂的处理来实现 DB 风格的隔离。这种组合在 Hibernate 6 中可能根本不可能。在许多线程中运行压力测试之前,您可能不会遇到问题,顺序调用通常可以正常工作。

如果你坚持将它们存储到同一个缓存中,你可以尝试设置hibernate.cache.keys_factory=default(我希望你的WF版本已经包含这个设置,新版本应该已经默认了)。

详情请参阅https://hibernate.atlassian.net/browse/HHH-11083https://hibernate.atlassian.net/browse/HHH-10287

【讨论】:

  • 谢谢。我已按照建议添加了默认缓存键实现,并且在启动时收到错误 Unable to resolve name [default] as strategy [org.hibernate.cache.spi.CacheKeysFactory]。我正在使用 WF 10.1 附带的默认休眠 (5.0.10) 和 Infinispan (8.2.4)。
  • 我在我的问题中添加了更新。事实上你是对的。问题不在于同一区域的查询缓存和实体缓存。但是由于同一区域中的共享实体缓存。看起来 entitymanager.find (EntityXYZ.class, 4) 返回的对象与预期的对象不同。而且我认为所描述的解决方案在 5.0.x 版本中并不固定。
  • 另外,我不想将所有实体都保留在共享缓存区域中。但我发现该应用程序的运行速度比早期 JBoss 缓存版本慢 3 倍,该版本为所有实体使用共享缓存区域。如果实体缓存在共享缓存区域而不是单独缓存,它是否提供任何性能提升?非常感谢任何提高性能的设置。谢谢
  • 我不认为使用共享缓存区域会给您带来任何好处; IMO 仅当您想限制资源使用(只能在每个缓存中完成)或将一些统计信息汇总在一起(尽管您可以总结一下......)时才有用。 Wrt 慢 3 倍:有一些错误修复在节点之间引入了更多的往返,特别是如果您使用分布式/复制缓存。这些操作修复了一些竞争条件。然而 3x 实在是太多了:你的命中/未命中率是否显着降低?
  • 我发现应用程序在新版本中添加了一些额外的步骤(如解组),因此可能是延迟。很抱歉比较不准确。
猜你喜欢
  • 2017-10-03
  • 2014-06-25
  • 2013-10-31
  • 2014-11-28
  • 2011-12-18
  • 2020-07-22
  • 2016-09-20
  • 1970-01-01
  • 2021-10-03
相关资源
最近更新 更多