Hibernate Infinispan 2LC:同一缓存区域中的查询缓存和实体缓存
Hibernate Infinispan 2LC : query cache and entity cache in same cache region
使用JBoss 缓存,可以毫无问题地将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
还包含本身声明为 cacheable
的 entities
并且具有与 regionA
相同的缓存区域。
现在执行,出现这个错误。我怀疑这是由于冲突,因为它们存储在同一区域并且它试图获取 returns 另一个对象的对象 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
尝试加载 2 的不同调用,例如 classes(在同一共享缓存 2LC 区域中)具有 @id
和 int
。正如 Flavius 指出的那样,id=4
似乎在 2 classes 之间很常见。
将以下配置添加到 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.run(PersistenceUnitServiceImpl.java:179)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.run(PersistenceUnitServiceImpl.java:121)
at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:667)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.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.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
,但它不起作用。错误不正确,因为 class 是指定 class.
的实现
<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)
查询缓存是字符串索引的,实体缓存是使用原始 ID 索引的(与 EntityXYZ 中标有 @Id
的 field/method 相同的对象)所以我想知道冲突是如何发生的发生在 id=4
.
无论如何,为实体和查询使用相同的区域(缓存)不是一个好主意——实体有时需要更复杂的处理来实现数据库式隔离。对于 Hibernate 6,这样的组合可能根本不可能。在您 运行 在许多线程中进行压力测试之前,您可能不会遇到问题,顺序调用通常可以正常工作。
如果你坚持要将它们存储在同一个缓存中,你可以尝试设置hibernate.cache.keys_factory=default
(我希望你的WF版本已经包含这个设置,新版本应该已经默认了)
详情见https://hibernate.atlassian.net/browse/HHH-11083 and https://hibernate.atlassian.net/browse/HHH-10287。
使用JBoss 缓存,可以毫无问题地将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
还包含本身声明为 cacheable
的 entities
并且具有与 regionA
相同的缓存区域。
现在执行,出现这个错误。我怀疑这是由于冲突,因为它们存储在同一区域并且它试图获取 returns 另一个对象的对象 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
尝试加载 2 的不同调用,例如 classes(在同一共享缓存 2LC 区域中)具有 @id
和 int
。正如 Flavius 指出的那样,id=4
似乎在 2 classes 之间很常见。
将以下配置添加到 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.run(PersistenceUnitServiceImpl.java:179)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.run(PersistenceUnitServiceImpl.java:121)
at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:667)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.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.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
,但它不起作用。错误不正确,因为 class 是指定 class.
<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)
查询缓存是字符串索引的,实体缓存是使用原始 ID 索引的(与 EntityXYZ 中标有 @Id
的 field/method 相同的对象)所以我想知道冲突是如何发生的发生在 id=4
.
无论如何,为实体和查询使用相同的区域(缓存)不是一个好主意——实体有时需要更复杂的处理来实现数据库式隔离。对于 Hibernate 6,这样的组合可能根本不可能。在您 运行 在许多线程中进行压力测试之前,您可能不会遇到问题,顺序调用通常可以正常工作。
如果你坚持要将它们存储在同一个缓存中,你可以尝试设置hibernate.cache.keys_factory=default
(我希望你的WF版本已经包含这个设置,新版本应该已经默认了)
详情见https://hibernate.atlassian.net/browse/HHH-11083 and https://hibernate.atlassian.net/browse/HHH-10287。