2010-02-18 5 views
8

Nehmen wir an, ich habe zwei Entitäten, Employee und Skill. Jeder Mitarbeiter hat eine Reihe von Fähigkeiten. Jetzt, wenn ich die Fähigkeiten träge durch die Employee Instanzen lade, wird der Cache nicht für Fähigkeiten in verschiedenen Instanzen von Employee verwendet.Wie verwende ich Second Level Cache für Lazy Loaded Collections in Hibernate?

Betrachten wir den folgenden Datensatz.

Employee - 1 : Java, PHP 
Employee - 2 : Java, PHP 

Wenn ich Mitarbeiter laden - 2 nach Mitarbeiter - 1, ich will die Fähigkeiten nicht überwintern die Datenbank zu schlagen zu erhalten und stattdessen die Skill Instanzen bereits im Cache verfügbar. Ist das möglich? Wenn das so ist, wie?

Hibernate Konfiguration

<session-factory> 
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> 
    <property name="hibernate.connection.password">pass</property> 
    <property name="hibernate.connection.url">jdbc:mysql://localhost/cache</property> 
    <property name="hibernate.connection.username">root</property> 
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> 

    <property name="hibernate.cache.use_second_level_cache">true</property> 
    <property name="hibernate.cache.use_query_cache">true</property> 
    <property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property> 
    <property name="hibernate.hbm2ddl.auto">update</property> 
    <property name="hibernate.show_sql">true</property> 

    <mapping class="org.cache.models.Employee" /> 
    <mapping class="org.cache.models.Skill" /> 
</session-factory> 

Die Entitäten mit Importen, Getter und Setter entfernt

@Entity 
@Table(name = "employee") 
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
public class Employee { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private int id; 

    private String name; 

    public Employee() { 
    } 

    @ManyToMany 
    @JoinTable(name = "employee_skills", joinColumns = @JoinColumn(name = "employee_id"), inverseJoinColumns = @JoinColumn(name = "skill_id")) 
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    private List<Skill> skills; 
} 

@Entity 
@Table(name = "skill") 
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
public class Skill { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private int id; 

    private String name; 
} 

SQL für das Laden der zweiten Mitarbeiter und seine Fähigkeiten

Hibernate: select employee0_.id as id0_0_, employee0_.name as name0_0_ from employee employee0_ where employee0_.id=? 
Hibernate: select skills0_.employee_id as employee1_1_, skills0_.skill_id as skill2_1_, skill1_.id as id1_0_, skill1_.name as name1_0_ from employee_skills skills0_ left outer join skill skill1_ on skills0_.skill_id=skill1_.id where skills0_.employee_id=? 

Dabei möchte ich insbesondere die zweite Abfrage vermeiden, da die erste sowieso unvermeidlich ist.

Antwort

4

Sie müssen die Employee--<>Skills Assoziation zwischenspeichern. Beispiel aus Speed Up Your Hibernate Applications with Second-Level Caching unter:

<hibernate-mapping package="com.wakaleo.articles.caching.businessobjects"> 
    <class name="Employee" table="EMPLOYEE" dynamic-update="true"> 
     <meta attribute="implement-equals">true</meta>  

     <id name="id" type="long" unsaved-value="null" > 
      <column name="emp_id" not-null="true"/> 
      <generator class="increment"/> 
     </id> 

    <property column="emp_surname" name="surname" type="string"/> 
    <property column="emp_firstname" name="firstname" type="string"/> 

    <many-to-one name="country" 
      column="cn_id" 
       class="com.wakaleo.articles.caching.businessobjects.Country" 
      not-null="true" /> 

    <!-- Lazy-loading is deactivated to demonstrate caching behavior -->  
    <set name="languages" table="EMPLOYEE_SPEAKS_LANGUAGE" lazy="false"> 
     <cache usage="read-write"/> 
     <key column="emp_id"/> 
      <many-to-many column="lan_id" class="Language"/> 
    </set>        
    </class> 
</hibernate-mapping> 

Hinweis das <cache> Element innerhalb der Sprachen.

+0

Ich habe das schon gemacht. Es vermeidet die Abfrage nur für diejenigen Mitarbeiter, die bereits geladen sind. Nicht Angestellte, die nicht im Cache sind und die gleichen Fähigkeiten wie ein anderer Mitarbeiter im Cache haben. In meinem ersten Beispiel würde es funktionieren, wenn ich Employee - 1 wieder lade, aber nicht wenn ich Employee - 2 lade. –

+0

@Chandru Können Sie bitte Ihre Mappings ** und ** die generierte SQL zeigen? –

+0

I'ev hat meine Frage aktualisiert, um die Informationen hinzuzufügen. –