为什么80%的码农都做不了架构师?>>>
一 简介
在hibernate框架中,使用缓存来减少对数据库的访问,以此来提高响应速度。hibernate中提供了三种缓存可供使用,分别是一级缓存、二级缓存、查询缓存。
其中一级缓存是session级别的缓存,缓存周期即为session的寿命。同一个session进行的对象查询,无论是诸如session.get(Class arg0, Seralizable arg1)这样通过session直接调用的方法,还是该session下的query发起的hql查询,包括list查询,被取出的对象或对象集合都会被存在该session下的一级缓存中,以map<key, value>形式存储,key为主键,value为对象。因为key值是主键,所以只有使用主键查询的方法才可以使用该一级缓存,也就是只有三个方法可以使用
session.get(Class arg0, Seralizable arg1);
session.load(Class arg0, Seralizable arg1);
query.iterate();
*注意* query.iterate()与list()方法不同的是,调用时会发出一条sql语句,只查询主键值,并不查询整个对象。在遍历时,会根据主键值先去一级缓存中查找是否有匹配的,若匹配,返回该缓 存,不匹配,则去数据库中进行查询,但此时查询是单独发出一条sql语句,只查询一个对象,查询主键匹配的数据。这意味着,若此时一级缓存没有一条匹配,则整个遍历过程会发出 N + 1 条sql语句,而在最好的情况下则只产生一条查询ID列的sql语句
因为所有查询都放入了一级缓存,大数据量查找可能导致内存溢出,hibernate提供了以下两种方法对一级缓存进行清除
session.clear();
session.evict(arg0);
二级缓存是sessionFactory级别的缓存,缓存周期即为sessionFactory的寿命。二级缓存在使用上类似于一级缓存,只是作用范围不再局限于同一个session,并且需先指定使用的类才可以使用二级缓存。
查询缓存对所有hql发出的查询都有效,前提是必须先设置才能使用,设置方法在下文。设置完后,同样的hql查询就不会在去数据库进行查询。
二 配置及使用测试
以下例程定义了一个简单的POJO类:Position.java,使用JUnit,hibernate版本为hibernate4.14final
1 一级缓存,一级缓存不用进行任何设置,hibernate原生支持:
/**
* 一级缓存测试,session级别,同一session下只查询一次,此处只发出一条sql语句
* 不需要设置即可使用
*/
@Test
public void testA(){
Session session = HibernateUtil.getSession();
Position pos1 = (Position) session.get(Position.class, 22);
Position pos2 = (Position) session.get(Position.class, 22);
System.out.println(pos1);
System.out.println(pos2);
}
2 二级缓存
/**
* 二级缓存测试,sessionFactory级别,不同session下只查询一次,只输出一条sql语句
* 二级缓存需进行相关设置
* 1 引入jar包:hibernate-ehcache-4.1.4.Final.jar,ehcache-core-2.4.3.jar
* 2 在hibernate.cfg.xml文件中开启二级缓存,并指定二级缓存产品提供商
* <property name="hibernate.cache.user_second_level_cache">true</property>
* <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
* 3 在hibernate.cfg.xml文件中或者实体类映射文件中指定实体类使用
* <class-cache usage="read-only" class="com.bean.Position"/>
* 或者在其映射文件中
* <cache usage="read-only"/>
* 4 之前的版本需设置ehcache.xml文件,此处省去,经测试正常
*/
@Test
public void testB(){
Session session1 = HibernateUtil.getSession();
Session session2 = HibernateUtil.getSession();
Position pos1 = (Position) session1.get(Position.class, 1);
Position pos2 = (Position) session2.get(Position.class, 1);
System.out.println(pos1);
System.out.println(pos2);
}
3 查询缓存
/**
* 查询缓存测试
* 1 使用前需开启二级缓存
* 2 在hibernate.cfg.xml文件中开启查询缓存
* <property name="hibernate.cache.use_query_cache">true</property>
* 3 在query在query.setCacheable(true),即使用查询缓存
* 4 这样相同的hql语句就不会再去数据库查询
*/
@Test
public void testC(){
Session session = HibernateUtil.getSession();
String hql = "from Position";
List<Position> list1 = session.createQuery(hql).setCacheable(true).list();
List<Position> list2 = session.createQuery(hql).setCacheable(true).list();
System.out.println(list1);
System.out.println(list2);
}
4 iterator测试
/**
* 因为list()查询完后结果保存在缓存了,此处在list()后只有一条sql语句
*/
@Test
public void testD(){
Session session = HibernateUtil.getSession();
String hql = "from Position";
List<Position> list = session.createQuery(hql).list();
System.out.println(list);
Iterator<Position> iterator = session.createQuery(hql).iterate();
System.out.println("--- iterator ");
while(iterator.hasNext()){
System.out.println("Iterator " + iterator.next());
}
}