类级别的二级缓存只适用于get和load获取数据,对query接口可以将数据放置到类级别的二级缓存中(前提是对应的类设置了二级缓存),但是不能使用query接口的list方法从缓存中获取数据;
前提:session不是线程安全,并未绑定在ThreadLocal中。Dept已经配置了二级缓存
@Test
public void test2(){
Query query = session.createQuery("from Dept where deptno = 10");
query.list();
transaction.commit();
session.close();
session = HibernateUtils.openSession();
transaction = session.beginTransaction();
List list = query.list();
System.out.println(list);
}
结果会报错:org.hibernate.SessionException: Session is closed!
@Test
public void test2(){
Query query = session.createQuery("from Dept where deptno = 10");
query.list();
transaction.commit();
session.close();
session = HibernateUtils.openSession();
transaction = session.beginTransaction();
Dept dept = (Dept) session.get(Dept.class, 10);
System.out.println(dept);
}
结果:
Hibernate:
select
dept0_.DEPTNO as DEPTNO1_0_,
dept0_.DNAME as DNAME2_0_,
dept0_.LOC as LOC3_0_
from
DEPT dept0_
where
dept0_.DEPTNO=10
Dept [deptno=10, dname=ACCOUNTING, loc=NEW YORK]
没有报错,只发出一条sql语句。说明get()、load()方法可以获取二级缓存中的数据,但是query.list()不可以,而因为Dept设置了二级缓存,所以数据可以放到二级缓存中。
关于query.list()返回的List集合,从笔者的测试结果中作出以下推测:
在使用默认设置的情况下,每次调用query.list()都会发出sql语句去查询数据库中的记录而不会检查缓存中是否有相应的记录。如果设置了查询缓存,query.list()就可以查询缓存中的记录,没有结果才去查询数据库中的记录。虽然可以查询缓存,但是也只能查询session中的缓存,即只能查询一级缓存。
@Test
public void testQueryCache(){
Query query = session.createQuery("from Dept");
query.setCacheable(true);
List list = query.list();
System.out.println(list.size());
transaction.commit();
session.close();
session = HibernateUtils.openSession();
transaction = session.beginTransaction();
Dept dept2 = (Dept) session.get(Dept.class, 10);
System.out.println(dept2);
query = session.createQuery("from Dept");
list = query.list();
System.out.println(list.size());
}
得到的结果是:
Hibernate:
select
dept0_.DEPTNO as DEPTNO1_0_,
dept0_.DNAME as DNAME2_0_,
dept0_.LOC as LOC3_0_
from
DEPT dept0_
4
Dept [deptno=10, dname=ACCOUNTING, loc=NEW YORK]
Hibernate:
select
dept0_.DEPTNO as DEPTNO1_0_,
dept0_.DNAME as DNAME2_0_,
dept0_.LOC as LOC3_0_
from
DEPT dept0_
4
由此可以看出,就算二级缓存中有数据,但是只要使用query.list(),都需要先用session来创建Query对象然后再查询一级缓存中的数据,就算二级缓存中有相应的数据也查询不到。
设置查询缓存
在hibernate.cfg.xml文件中添加
<property name="cache.use_query_cache">true</property>
然后在使用query.list()之前设置:
query.setCacheable(true);