Как использовать кэш второго уровня для отложенных загрузок в Hibernate?

Допустим, у меня есть две сущности, Employee а также Skill, У каждого сотрудника есть набор навыков. Теперь, когда я лениво загружаю навыки через Employee экземпляры кеш не используется для навыков в разных случаях Employee,

Давайте рассмотрим следующий набор данных.

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

Когда я загружаю Employee - 2 после Employee - 1, я не хочу, чтобы hibernate попадал в базу данных, чтобы получить навыки, и вместо этого использовал Skill экземпляры уже доступны в кеше. Это возможно? Если так, как?

Конфигурация гибернации

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

Объекты с импортом, геттерами и сеттерами удалены

@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 для загрузки второго сотрудника и его навыков

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=?

В этом я специально хочу избежать второго запроса, так как первый в любом случае неизбежен.

1 ответ

Вам необходимо кэшировать Employee--<>Skills ассоциация. Пример, взятый из " Ускорение ваших приложений Hibernate с кэшированием второго уровня" ниже:

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

Обратите внимание <cache> элемент внутри языков.

Другие вопросы по тегам