1. 注意session.clear()的运用,尤其是在不断分页循环的时候
a.在一个大集合中进行遍历,遍历msg,取出其中含有敏感字体的对象
b.另外一种形式的内存泄漏 // java有内存泄漏吗? 代码级别没有,实际操作中会有,例如:打开数据库、读文件不关闭链接,hibernate的分页没有进行session.clear()
2. 1+N问题(典型面试题)
例如:一个Category,对应一个topic,Category和topic各有10条,当想取出所有topic时,默认hibernate会发出1+10(取10个category)条sql语句,这种情况被称为1+N问题。
a和c根据具体情况使用
解决方案: a. 把fetchtype设成lazy
b.@BatchSize(size=5) 设置在Category的类名上(此方案不特别好)
c. join fetch
使用session.createCriteria(Topic.class),默认使用join fetch,只发出一条sql语句
3. list和iterate(不太重要,一般情况下用list(),面试可能会问)
a. list取所有
b. iterate先取ID,等用到的时候再根据ID取对象
c. session中list第二次发出,仍会查询数据库
d.iterate第二次,首先找session缓存
4. 一级缓存、查询缓存、查询缓存(面试题)
a. 什么是缓存
经常被访问的数据,存放到内存中,便于访问
b. 什么是一级缓存
session级别的缓存
e.g. 同一个session,load某条数据两次,但hibernate只发出一条sql语句(即只查询一次数据库),因为第二次已从缓存中取得结果
不同的session,各load某条数据一次,hibernate还是发出两条sql语句,它们的session缓存不共享
c. 什么是二级缓存
SessionFactory级别的缓存,可以跨越session存在(让多个session共享同一块缓存)
什么样的数据适合放入二级缓存?e.g. 组织机构、用户权限等
1. 经常被访问
2. 改动不大不会经常改动
3. 数量有限
d. 打开二级缓存
hibernate.cfg.xml中设定
<property name="cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
添加ehcache.xml文件
...
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
...
给需要二级缓存的对象,配置二级缓存
@Entity
@Cache(usage =CacheConcurrencyStrategy.READ_WRITE // 放到二级缓存中可读可改
,region = "sampleCache1") // 二级缓存的名字 对应ehcache.xml文件中的名字
public class Category {
private int id;
private String name;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
e. load默认用二级缓存,iterate默认用二级缓存
f. list默认向二级缓存加数据,但查询的时候不用二级缓存(因为查询的条件不同,没发用;如果查询条件相同时,可以从二级缓存查,这种缓存被称为查询缓存(三级缓存))
g. 如果query需要用二级缓存,第一步:那么需要打开查询缓存
<property name="hibernate.cache.use_query_cache">true</property>
第二步:需要在查询的时候设置一些参数
Query q = session.createQuery(” from Category “);
(List)q.setCacheable(true).list();
// 只发一条sql语句
@Test
public void testQueryCache(){
Session session = sf.getCurrentSession();
session.beginTransaction();
Query q = session.createQuery(" from Category ");
List<Category> categories = (List<Category>)q.setCacheable(true).list();
for(Category c:categories){
System.out.println(c.getName());
}
session.getTransaction().commit();
Session session2 = sf.getCurrentSession();
session2.beginTransaction();
Query q2 = session2.createQuery(" from Category ");
List<Category> categories2 = (List<Category>)q2.setCacheable(true).list();
for(Category c:categories2){
System.out.println(c.getName());
}
session2.getTransaction().commit();
}