转载自:http://www.360doc.com/content/14/0801/16/1073512_398635409.shtml
Hibernate缓存
缓存的意思是将一部分数据保存到内存中或者是保存到本地硬盘上,从而提供访问效率。
1、一级缓存(session级别)
一级缓存属于Session级别的,当session对象调用save()方法保存一个对象后,该对象会被放入到session的缓存中,当session对象调用get()或load()方法从数据库取出一个对象后,该对象也会被放入到session的缓存中。
//此时会发出一条sql,将所有学生全部查询出来,并放到session的一级缓存当中 List<Student> stus = (List<Student>)session.createQuery("from Student") .setFirstResult(0) . setMaxResults(30).list(); // 当再次查询学生信息时,会首先去缓存中看是否存在,如果不存在,再去数据库中查询 Student stu = (Student)session.load(Student.class, 1);
此时hibernate仅仅只会发出一条 sql 语句,因为第一行代码就会将整个的对象查询出来,放到session的一级缓存中去,当我如果需要再次查询学生对象时,此时首先会去缓存中看是否存在该对象,如果存在,则直接从缓存中取出,就不会再发sql了,但是要注意一点:hibernate的一级缓存是session级别的,所以如果session关闭后,缓存就没了,此时就会再次发sql去查数据库。
2、二级缓存(sessionFactory级别)
2.1 使用hibernate二级缓存,我们首先需要对其进行配置,有以下四个配置步骤:
1)导入JAR包:
hibernate并没有提供相应的二级缓存的组件,所以需要加入额外的二级缓存包,常用的二级缓存包是EHcache。这个我们在下载好的hibernate的lib->optional->ehcache下可以找到(我这里使用的hibernate4.1.7版本),然后将里面的几个jar包导入即可。
2)在hibernate.cfg.xml配置文件中配置二级缓存的属性;
<!-- 开启二级缓存 --> <property name="hibernate.cache.use_second_level_cache">true</property> <!-- 二级缓存的提供类 在hibernate4.0版本以后我们都是配置这个属性来指定二级缓存的提供类--> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <!-- 二级缓存配置文件的位置 --> <property name="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</property>
3)配置hibernate的二级缓存是通过使用 ehcache的缓存包,所以我们需要创建一个 ehcache.xml 的配置文件,来配置我们的缓存信息,将其放到项目根目录下
1 <ehcache> 2 3 <!-- Sets the path to the directory where cache .data files are created. 4 5 If the path is a Java System Property it is replaced by 6 its value in the running VM. 7 8 The following properties are translated: 9 user.home - User's home directory 10 user.dir - User's current working directory 11 java.io.tmpdir - Default temp file path --> 12 13 <!--指定二级缓存存放在磁盘上的位置--> 14 <diskStore path="user.dir"/> 15 16 <!--我们可以给每个实体类指定一个对应的缓存,如果没有匹配到该类,则使用这个默认的缓存配置--> 17 <defaultCache 18 maxElementsInMemory="10000" //在内存中存放的最大对象数 19 eternal="false" //是否永久保存缓存,设置成false 20 timeToIdleSeconds="120" 21 timeToLiveSeconds="120" 22 overflowToDisk="true" //如果对象数量超过内存中最大的数,是否将其保存到磁盘中,设置成true 23 /> 24 25 <!-- 26 1、timeToLiveSeconds的定义是:以创建时间为基准开始计算的超时时长; 27 2、timeToIdleSeconds的定义是:在创建时间和最近访问时间中取出离现在最近的时间作为基准计算的超时时长; 28 3、如果仅设置了timeToLiveSeconds,则该对象的超时时间=创建时间+timeToLiveSeconds,假设为A; 29 4、如果没设置timeToLiveSeconds,则该对象的超时时间=max(创建时间,最近访问时间)+timeToIdleSeconds,假设为B; 30 5、如果两者都设置了,则取出A、B最少的值,即min(A,B),表示只要有一个超时成立即算超时。 31 32 --> 33 34 <!--可以给每个实体类指定一个配置文件,通过name属性指定,要使用类的全名--> 35 <cache name="com.xiaoluo.bean.Student" 36 maxElementsInMemory="10000" 37 eternal="false" 38 timeToIdleSeconds="300" 39 timeToLiveSeconds="600" 40 overflowToDisk="true" 41 /> 42 43 <cache name="sampleCache2" 44 maxElementsInMemory="1000" 45 eternal="true" 46 timeToIdleSeconds="0" 47 timeToLiveSeconds="0" 48 overflowToDisk="false" 49 /> --> 50 51 52 </ehcache>
4)开启二级缓存
①如果使用xml配置,我们需要在 Student.hbm.xml 中加上一下配置:
二级缓存的使用策略一般有这几种:read-only、nonstrict-read-write、read-write、transactional。注意:我们通常使用二级缓存都是将其配置成 read-only ,即我们应当在那些不需要进行修改的实体类上使用二级缓存,否则如果对缓存进行读写的话,性能会变差,这样设置缓存就失去了意义。
<hibernate-mapping package="com.xiaoluo.bean"> <class name="Student" table="t_student"> <!-- 二级缓存一般设置为只读的 --> <cache usage="read-only"/> <id name="id" type="int" column="id"> <generator class="native"/> </id> <property name="name" column="name" type="string"></property> <property name="sex" column="sex" type="string"></property> <many-to-one name="room" column="rid" fetch="join"></many-to-one> </class> </hibernate-mapping>
②如果使用annotation配置,我们需要在Student这个类上加上这样一个注解:
@Entity @Table(name="t_student") @Cache(usage=CacheConcurrencyStrategy.READ_ONLY) // 表示开启二级缓存,并使用read-only策略 public class Student { private int id; private String name; private String sex; private Classroom room; ....... }
至此,二级缓存配置完毕;
2.2 二级缓存注意事项
如果我们只是取出对象的一些属性的话,则不会将其保存到二级缓存中去,因为二级缓存缓存的仅仅是对象;
try{ session = HibernateUtil.openSession(); /** * 注意:二级缓存中缓存的仅仅是对象,而下面这里只保存了姓名和性别两个字段,所以 不会被加载到二级缓存里面 */ List<Object[]> ls = (List<Object[]>) session .createQuery("select stu.name, stu.sex from Student stu") .setFirstResult(0).setMaxResults(30).list(); } catch (Exception e) { e.printStackTrace(); } finally { HibernateUtil.close(session); } try { /** * 由于二级缓存缓存的是对象,所以此时会发出两条sql */ session = HibernateUtil.openSession(); Student stu = (Student) session.load(Student.class, 1); System.out.println(stu); } catch (Exception e) { e.printStackTrace(); } }
2.3 二级缓存使用范围
什么样的数据适合存放到第二级缓存中?
1) 很少被修改的数据
2) 不是很重要的数据,允许出现偶尔并发的数据
3) 不会被并发访问的数据
4) 常量数据
不适合存放到第二级缓存的数据?
1) 经常被修改的数据
2) 绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发
3) 与其他应用共享的数据。
3、三级缓存(查询缓存-sessionFactory级别)
我们如果要配置查询缓存,只需要在hibernate.cfg.xml中加入一条配置即可:
<!-- 开启查询缓存 --> <property name="hibernate.cache.use_query_cache">true</property>
然后我们如果在查询hql语句时要使用查询缓存,就需要在查询语句后面设置这样一个方法:
List<Student> ls = session.createQuery("from Student where name like ?") .setCacheable(true) //开启查询缓存,查询缓存也是SessionFactory级别的缓存 .setParameter(0, "%王%") .setFirstResult(0).setMaxResults(50).list();
如果是在annotation中,我们还需要在这个类上加上这样一个注解:@Cacheable 。