Wie verwende ich den Cache der zweiten Ebene von Hibernate mit JPA?

Ich implementiere einen auf Entity Attribute Value basierenden Persistenzmechanismus. Der gesamte Datenbankzugriff erfolgt über den Ruhezustand. Ich habe eine Tabelle, die Pfade für Knoten enthält, es ist extrem einfach, nur eine ID und ein Pfad (String). Die Anzahl der Pfade wäre gering, etwa einige Tausend.

Die Haupttabelle enthält Millionen von Zeilen, und anstatt die Pfade zu wiederholen, habe ich die Pfade zu ihrer eigenen Tabelle normalisiert. Folgendes Verhalten möchte ich beim Einfügen in die Haupttabelle

1) Prüfen Sie, ob der Pfad in der Pfadtabelle vorhanden ist (Abfrage über Entity Manager, Pfadwert als Parameter verwenden)

2) Wenn es nicht existiert, füge es ein und erhalte die ID (über den Entity Manager)

3) Geben Sie id als Fremdschlüssel in die Haupttabellenzeile ein und fügen Sie diese in die Haupttabelle ein.

Dies wird Tausende Male für eine Reihe von Domänenobjekten passieren, die vielen Zeilen in der Haupttabelle und einigen anderen Tabellen entsprechen. Die obigen Schritte werden also mit einer einzigen Transaktion wie der folgenden wiederholt:

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

Wenn ich Schritt 2 durchführe, führt dies zu einem enormen Leistungsabfall bei der Gesamtoperation. Es bittet um Zwischenspeicherung, da diese Tabelle nach einer Weile höchstens 10-20.000 Einträge mit sehr seltenen neuen Einfügungen enthalten wird. Ich habe versucht, dies mit Hibernate zu tun, und fast 2 Tage verloren.

Ich verwende Hibernate 4.1 mit JPA-Anmerkungen und ECache. Ich habe versucht, das Zwischenspeichern von Abfragen zu aktivieren, auch wenn ich in allen Einfügungen dasselbe Abfrageobjekt verwendet habe, wie unten gezeigt:

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();
        }

Die NodePath-Entität wird wie folgt mit Anmerkungen versehen:

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

Der Abfragecache wird verwendet, soweit aus der Statistik ersichtlich, es wird jedoch keine Verwendung für den Cache der zweiten Ebene gemeldet:

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
....

Eine einfache, handgeschriebene Hash-Tabelle als Cache funktioniert wie erwartet und verkürzt die Gesamtzeit drastisch. Ich schätze, ich kann das Caching von Hibernate aufgrund der Art meiner Operationen nicht auslösen.

Wie verwende ich den Cache der zweiten Ebene des Ruhezustands mit diesem Setup? Für das Protokoll ist dies meine Persistenz 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>

Antworten auf die Frage(1)

Ihre Antwort auf die Frage