2017-05-12 4 views
2

En utilisant JBoss Cache, il était possible de stocker le cache entity et le cache query dans la même région de cache sans aucun problème. Mais une fois migré à wildfly 10 (avec infinispan comme 2LC), il semble y avoir un problème.Hibernate Infinispan 2LC: cache de requête et cache d'entité dans la même région de cache

J'ai fourni la région de cache pour l'entité comme ci-dessous.

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

et le cache de requête comme

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

Il est important de noter que le query ci-dessus contient aussi le entities qui se sont déclarés comme cacheable et a même région de cache regionA.

Maintenant, lors de l'exécution, il y a cette erreur. Je soupçonne que c'est dû au conflit car ils sont stockés dans la même région et il essaye d'aller chercher l'identifiant d'objet qui renvoie un autre objet. Mais quelqu'un peut-il jeter de la lumière. Est-ce vraiment le cas? et expliquer plus sur l'erreur?

Mais la même chose fonctionne dans le cache JBoss dans JBoss 5. Est-ce que infinispan gère différemment? Ou est-ce problème 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 

MISE À JOUR:

Les entitymanager tente de charger dans les différents appels de ces classes 2 (dans la même cache partagée région 2LC) qui a @id comme int. Comme Flavius ​​l'a souligné, le id=4 semble être commun entre 2 classes.

Lors de l'ajout ci-dessous de la configuration à persistence.xml, une erreur de démarrage s'est produite.

persistence.xml

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

erreur

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) 

MISE A JOUR 2

J'ai changé pour fournir le default à FQN exacte, mais il ne ne fonctionne pas. L'erreur n'est pas correcte car la classe est l'implémentation de la classe spécifiée.

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

erreur:

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) 
+0

Selon JIRA, il semble que le problème avec DefaultCacheKeysFactory a été corrigé dans 5.0.12, 5.1.3 et 5.2.5. Habituellement, vous devriez pouvoir mettre à jour manuellement le module hibernate-orm de WF à 5.0.12 (comme pour toute version micro). –

+0

Merci. S'il n'y a pas de gain de performance dû à la région du cache partagé, alors je m'en tiendrai aux meilleures pratiques. – ulab

Répondre

3

cache de requêtes est indexé chaîne, et le cache de l'entité est indexée soit à l'aide ids premières (le même objet que le champ/méthode marquée avec @Id en EntityXYZ) donc je me demande comment le conflit pourrait se produire sur id=4.De toute façon, ce n'est pas une bonne idée d'utiliser la même région (cache) pour les entités et les requêtes - les entités ont parfois besoin d'une gestion plus complexe pour obtenir une isolation de style DB. Une telle combinaison peut ne pas être possible du tout avec Hibernate 6. Vous ne pouvez pas toucher les problèmes avant d'avoir effectué des tests de stress dans de nombreux threads, l'invocation séquentielle fonctionne habituellement bien.

Si vous insistez pour les stocker dans le même cache, vous pouvez essayer de définir hibernate.cache.keys_factory=default (J'espère que votre version WF contient déjà ce paramètre, les versions plus récentes devraient l'avoir déjà par défaut). Pour plus de détails, voir https://hibernate.atlassian.net/browse/HHH-11083 et https://hibernate.atlassian.net/browse/HHH-10287.

+1

Merci. J'ai ajouté l'implémentation de clé de cache par défaut comme suggéré et j'obtiens l'erreur 'Impossible de résoudre le nom [par défaut] en tant que stratégie [org.hibernate.cache.spi.CacheKeysFactory]' au démarrage. J'utilise le hibernate par défaut (5.0.10) et Infinispan (8.2.4) qui vient avec WF 10.1. – ulab

+0

J'ai ajouté une mise à jour dans ma question. En fait, vous avez raison. Le problème n'est pas avec le cache de requête et le cache d'entité dans la même région. Mais en raison de cache d'entité partagée dans la même région. Il semble que entitymanager.find (EntityXYZ.class, 4) renvoie un objet différent de ce qui est attendu. Et je pense que la solution décrite n'est pas corrigée dans les versions 5.0.x. – ulab

+0

Aussi, je ne voudrais pas garder toutes les entités dans la région du cache partagé. Mais je trouve l'application exécutée 3 fois plus lente que la version antérieure du cache JBoss qui utilise une région de cache partagée pour toutes les entités. Fournit-il un gain de performance si les entités sont mises en cache dans la zone de cache partagé séparément? Tout paramètre permettant d'améliorer les performances est très apprécié. Merci – ulab