Let's say I have two entities, Employee
and Skill
. Every employee has a set of skills. Now when I load the skills lazily through the Employee
instances the cache is not used for skills in different instances of Employee
.
Let's Consider the following data set.
Employee - 1 : Java, PHP
Employee - 2 : Java, PHP
When I load Employee - 2 after Employee - 1, I do not want hibernate to hit the database to get the skills and instead use the Skill
instances already available in cache. Is this possible? If so how?
Hibernate Configuration
<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>
The Entities with imports, getters and setters Removed
@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 for Loading the Second Employee and his Skills
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=?
In that I specifically want to avoid the second query as the first one is unavoidable anyway.
A Hibernate second-level cache is one of the data caching components available in the Hibernate object-relational mapping (ORM) library. Hibernate is a popular ORM library for the Java language, and it lets you store your Java object data in a relational database management system (RDBMS).
Performance degrade. Yes, having caching do NOT necessary to give you better performance. Hibernate needs to do extra work to store and update the cache. If the entities cached are changed frequently and you are not querying them frequently, enabling the cache is just adding unnecessary extra burden.
You need to cache the Employee--<>Skills
association. Example taken from Speed Up Your Hibernate Applications with Second-Level Caching below:
<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>
Note the <cache>
element inside the of languages.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With