一、缓存的概念:
以空间换时间;
二、Hibernate缓存的分类:
前面我们讲的缓存都是session缓存;也叫一级缓存;get,load等缓存都是内置的,一级缓存;
SessionFactory缓存,二级缓存;
这里以Class —— Student,1对多的关系(单向)来例子说明下:
Class.java:
package com.cy.model; public class Class { private int id; private String name; 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; } }
Student.java:
package com.cy.model; import com.cy.model.Class; public class Student { private int id; private String name; private Class c; 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; } public Class getC() { return c; } public void setC(Class c) { this.c = c; } }
Class.hbm.xml:
<hibernate-mapping package="com.cy.model"> <class name="Class" table="t_class"> <id name="id" column="classId"> <generator class="native"></generator> </id> <property name="name" column="className"></property> </class> </hibernate-mapping>
Student.hbm.xml:
<hibernate-mapping package="com.cy.model"> <class name="Student" table="t_student"> <id name="id" column="stuId"> <generator class="native"></generator> </id> <property name="name" column="stuName"></property> <many-to-one name="c" class="com.cy.model.Class" column="classId" cascade="save-update"></many-to-one> </class> </hibernate-mapping>
StudentTest.java:
package com.cy.service; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.cy.model.Class; import com.cy.util.HibernateUtil; public class StudentTest { private SessionFactory sessionFactory=HibernateUtil.getSessionFactory(); private Session session; @Before public void setUp() throws Exception { session=sessionFactory.openSession(); session.beginTransaction(); } @After public void tearDown() throws Exception { session.getTransaction().commit(); session.close(); } /** * 同一个session中,同一个事务是有一级缓存的; */ @Test public void testCache1(){ Class c = (Class) session.get(Class.class, 1); System.out.println(c.getName()); Class c2 = (Class) session.get(Class.class, 1); System.out.println(c2.getName()); System.out.println(c == c2); /* * Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=? 08计算机本科 08计算机本科 true 第一次取c1的时候,已经将取出来的数据c1放到缓存中。 第二次取c2的时候,是有session缓存的。首选从缓存中找,找到,直接从缓存中拿,而不到数据库中去取了。 两个是同一个OID对象; */ } /** * 在不同的事务中,是否有缓存? */ @Test public void testCache2(){ Session session1 = sessionFactory.openSession(); session1.beginTransaction(); Class c = (Class) session1.get(Class.class, 1); System.out.println(c.getName()); session1.getTransaction().commit(); session1.close(); Session session2 = sessionFactory.openSession(); session2.beginTransaction(); Class c2 = (Class) session2.get(Class.class, 1); System.out.println(c2.getName()); session2.getTransaction().commit(); session2.close(); System.out.println(c == c2); /* * Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=? 08计算机本科 Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=? 08计算机本科 false 虽然在同一个session中有缓存,但是这里新开辟了一个事务,发出两个sql 不同的事务是不能共用一级缓存的。 一级缓存只适用于同一个session,同一个事务; */ } }
三、二级缓存策略提供商:
配置ehcache二级缓存,让不同的session,不同的事务能共享数据。
要用到SessionFactory缓存了;
使用到的ehcache相关的jar包:
jar包在hibernate压缩包中:
hibernate-release-4.3.5.Finalliboptionalehcache
可以参考hibernate压缩包中的hibernate-ehcache的配置:
hibernate-release-4.3.5.Finalprojecthibernate-ehcachein
hibernate-release-4.3.5.Finalprojecthibernate-ehcacheinhibernate-configehcache.xml 以及hibernate.cfg.xml
代码实现:
1)ehcache.xml配置:
<ehcache> <!-- 指定一个文件目录,当EHCache把数据写到硬盘上时,将把数据写到这个目录下 --> <diskStore path="E:\ehcache"/> <!-- 设置缓存的默认数据过期策略 --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <!-- name 设置缓存的名字,他的取值为类的完整名字或者类的集合的名字; maxElementsInMemory 设置基于内存的缓存可存放的对象的最大数目 eternal 如果为true,表示对象永远不会过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds,默认为false; timeToIdleSeconds 设定允许对象处于空闲状态的最长时间,以秒为单位; timeToLiveSeconds 设定对象允许存在于缓存中的最长时间,以秒为单位; overflowToDisk 如果为true,表示当基于内存的缓存中的对象数目达到maxElementsInMemory界限,会把溢出的对象写到基于硬盘的缓存中; --> <!-- 设定具体的第二级缓存的数据过期策略 --> <cache name="com.cy.model.Class" maxElementsInMemory="1" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" /> </ehcache>
2)hibernate.cfg.xml中相关ehcache二级缓存的配置:
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!--数据库连接设置 --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property> <property name="connection.username">root</property> <property name="connection.password">root</property> <!-- 方言 --> <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property> <!-- 控制台显示SQL --> <property name="show_sql">true</property> <!-- 自动更新表结构 --> <property name="hbm2ddl.auto">update</property> <!-- 启用二级缓存 --> <property name="cache.use_second_level_cache">true</property> <!-- 配置使用的二级缓存的产品 --> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <!-- 配置启用查询缓存 --> <property name="cache.use_query_cache">true</property> <property name="net.sf.ehcache.configurationResourceName">ehcache.xml</property> <mapping resource="com/cy/model/Student.hbm.xml"/> <mapping resource="com/cy/model/Class.hbm.xml"/> </session-factory> </hibernate-configuration>
3)最后,Class.hbm.xml中配置使用cache:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.cy.model"> <class name="Class" table="t_class"> <cache usage="read-only"/> <id name="id" column="classId"> <generator class="native"></generator> </id> <property name="name" column="className"></property> </class> </hibernate-mapping>
4)测试代码:
/** * 配置了二级缓存ehcache后,再次进行测试: */ @Test public void testCache3(){ Session session1 = sessionFactory.openSession(); session1.beginTransaction(); Class c = (Class) session1.get(Class.class, 1); System.out.println(c.getName()); session1.getTransaction().commit(); session1.close(); Session session2 = sessionFactory.openSession(); session2.beginTransaction(); Class c2 = (Class) session2.get(Class.class, 1); System.out.println(c2.getName()); session2.getTransaction().commit(); session2.close(); System.out.println(c == c2); /* * Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=? 08计算机本科 08计算机本科 false 只有1条sql,说明在第2次查的时候,使用到了二级缓存。 */ }
四、什么数据适合放二级缓存中
一般这些信息都是只读;不能修改;