Comment puis-je utiliser Hibernate du cache de second niveau avec JPA?

Je me suis mise en œuvre d'un Attribut d'Entité base de la Valeur du mécanisme de persistance. Tous les DB d'accès se fait via Hibernate.
J'ai une table qui contient les chemins d'accès pour les nœuds, il est extrêmement simple, il suffit d'un identifiant et d'un chemin d'accès (string) Les chemins seront en petit nombre, autour de quelques milliers de personnes.

La table principale a des millions de lignes, et plutôt que de répéter les chemins, j'ai normalisé les chemins d'accès à leur propre table. Ce qui suit est le comportement que je veux, lors de l'insertion dans la table principale

1) Vérifier si le chemin d'accès existe dans les chemins de table (requête via le gestionnaire d'entités, en utilisant un chemin de valeur comme paramètre)

2) si elle n'existe pas, d'insertion et d'obtenir l'id (persistance via entity manager)

3) mettre l'id comme valeur de clé étrangère pour la table principale ligne, et insérer le dans la table principale.

Cela va arriver des milliers de fois pour un ensemble d'objets du domaine, qui correspondent à un grand nombre de lignes dans la table principale et quelques autres tables. Si les étapes ci-dessus sont répétées à l'aide d'une seule opération comme ceci:

    EntityTransaction t = entityManager.getTransaction();
    t.begin();
    //perform steps given above, check, and then persist etc..
    t.commit();

Quand je procède à l'étape 2, il introduit une énorme chute des performances de l'exploitation. C'est la mendicité pour la mise en cache, car après un certain temps que la table va être d'au plus 10-20k entrées à de très rares nouvelles plaquettes. J'ai essayé de le faire avec Hibernate, et a perdu près de 2 jours.

Je suis en utilisant Hibernate 4.1, avec des annotations JPA et ECache. J'ai essayé d'activer la mise en cache de requêtes, même en utilisant la même requête objet tout au long de l'insère, comme indiqué ci-dessous:

Query call = entityManager.createQuery("select pt from NodePath pt " +
                "where pt.path = :pathStr)");
        call.setHint("org.hibernate.cacheable", true);  
        call.setParameter("pathStr", pPath);
        List<NodePath> paths = call.getResultList();
        if(paths.size() > 1)
            throw new Exception("path table should have unique paths");
        else if (paths.size() == 1){
            NodePath path = paths.get(0);
            return path.getId();
        }
        else {//paths null or has zero size
            NodePath newPath = new NodePath();
            newPath.setPath(pPath);
            entityManager.persist(newPath);
            return newPath.getId();
        }

La NodePath entité est annoté comme suit:

@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name = "node_path", schema = "public")
public class NodePath implements java.io.Serializable {

Le cache de requête est utilisé, aussi loin que je peux voir dans les statistiques, mais pas de l'utiliser pour le cache de second niveau est signalé:

queries executed to database=1
query cache puts=1
query cache hits=689
query cache misses=1
....
second level cache puts=0
second level cache hits=0
second level cache misses=0
entities loaded=1
....

Simple, écrite à la main à la table de hachage comme un cache, fonctionne comme prévu, le fait de réduire le temps total de façon drastique. Je suppose que je ne suis pas pour déclencher de Hibernate mise en cache en raison de la nature de mes opérations.

Comment puis-je utiliser hibernate du cache de second niveau avec cette configuration? Pour le record, c'est ma persistance xml:

http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">

<provider>org.hibernate.ejb.HibernatePersistence</provider> 
<class>...</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

  <properties>
   <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
    <property name="hibernate.connection.password" value="zyx" />
    <property name="hibernate.connection.url" value="jdbc:postgresql://192.168.0.194:5432/testdbforml" />
    <property name="hibernate.connection.username" value="postgres"/>
    <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
    <property name="hibernate.search.autoregister_listeners" value="false"/>
    <property name="hibernate.jdbc.batch_size" value="200"/>
     <property name="hibernate.connection.autocommit" value="false"/> 
     <property name="hibernate.generate_statistics" value="true"/>
    <property name="hibernate.cache.use_structured_entries" value="true"/>

    <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.ehcache.SingletonEhCacheRegionFactory"/>              

  </properties>

  • Très intéressant!!! Je vous remercie pour la question & reponse 😉 +1
InformationsquelleAutor mahonya | 2012-05-15