Я пытаюсь кэшировать ленивые загруженные коллекции с помощью ehcache/hibernate в проекте Spring. Когда я выполняю session.get (Parent.class, 123) и просматриваю дочерние элементы несколько раз, каждый раз запрос выполняется для извлечения дочерних элементов. Родитель запрашивается только в первый раз, а затем разрешается из кеша.Коллекции, которые не читаются из hibernate/ehcache второго уровня-кеша
Возможно, что-то у меня отсутствует, но я не могу найти решение. См. Соответствующий код ниже.
Я использую Spring (3.2.4.RELEASE) Hibernate (4.2.1.Final) и Ehcache (2.6.6)
Родительский класс:
@Entity
@Table(name = "PARENT")
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, include = "all")
public class Parent implements Serializable {
/** The Id. */
@Id
@Column(name = "ID")
private int id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "parent")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private List<Child> children;
public List<Child> getChildren() {
return children;
}
public void setChildren(List<Child> children) {
this.children = children;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Parent that = (Parent) o;
if (id != that.id) return false;
return true;
}
@Override
public int hashCode() {
return id;
}
}
Класс ребенка:
@Entity
@Table(name = "CHILD")
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, include = "all")
public class Child {
@Id
@Column(name = "ID")
private int id;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "PARENT_ID")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Parent parent;
public int getId() {
return id;
}
public void setId(final int id) {
this.id = id;
}
private Parent getParent(){
return parent;
}
private void setParent(Parent parent) {
this.parent = parent;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Child that = (Child) o;
return id == that.id;
}
@Override
public int hashCode() {
return id;
}
}
контекст приложения:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>Parent</value>
<value>Child</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<!-- cache settings ehcache-->
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.region.factory_class"> org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.cache.use_structured_entries">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.transaction.factory_class"> org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory</prop>
<prop key="hibernate.transaction.jta.platform"> org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform</prop>
</props>
</property>
</bean>
TestCase Я бег:
@Test
public void testGetParentFromCache() {
for (int i = 0; i <3 ; i++) {
getEntity();
}
}
private void getEntity() {
Session sess = sessionFactory.openSession()
sess.setCacheMode(CacheMode.NORMAL);
Transaction t = sess.beginTransaction();
Parent p = (Parent) s.get(Parent.class, 123);
Assert.assertNotNull(p);
Assert.assertNotNull(p.getChildren().size());
t.commit();
sess.flush();
sess.clear();
sess.close();
}
В протоколирования я могу видеть, что первый раз 2 выполняется запросы получать родитель и получение детей. Кроме того, ведение журнала показывает, что дочерние объекты, а также коллекция хранятся в кеше второго уровня. Однако при чтении коллекции выполняется запрос для извлечения детей во второй и третьей попытках.
Поскольку EHCache не работал, мы также попробовали infinispan (с различным уровнем параллелизма). К сожалению, мы продолжаем испытывать ту же проблему.
P.S. Эта проблема также рассматривается в форуме Ehcache: http://forums.terracotta.org/forums/posts/list/8785.page и гибернации форум: https://forum.hibernate.org/viewtopic.php?f=1&t=1029899
Кроме того мой коллега создал пример проекта, напоминающего нашу установку проекта и проблемы на GitHub: https://github.com/basvanstratum/cacheimpl
Сессия, которую использует ваш тест, управляется весной, я полагаю? – aquaraga
Да, sessionFactory управляется весной. –
Чтобы убедиться, что ленивая загрузка не мешает проблеме, вы пробовали один и тот же тест, но с типом выборки, установленным в 'fetch = FetchType.EAGER' в коллекции? –