Hibernate提供的缓存
有一级缓存、二级缓存。 目的是为了减少对数据库的访问次数,提升程序执行效率!
一级缓存:
基于Session的缓存,缓存内容只在当前session有效,session关闭,缓存内容失效!
特点:
作用范围较小! 缓存的事件短。
缓存效果不明显。
概述
二级缓存:
Hibernate提供了基于应用程序级别的缓存, 可以跨多个session,即不同的session都可以访问缓存数据。 这个换存也叫二级缓存。
Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码。
如果用户觉得hibernate提供的框架框架不好用,自己可以换其他的缓存框架或自己实现缓存框架都可以。
二级缓存,使用步骤
1) 开启二级缓存
2)指定缓存框架
3)指定那些类加入二级缓存
4)测试
测试二级缓存!
缓存策略
<class-cache usage="read-only"/> 放入二级缓存的对象,只读;
<class-cache usage="nonstrict-read-write"/> 非严格的读写
<class-cache usage="read-write"/> 读写; 放入二级缓存的对象可以读、写;
<class-cache usage="transactional"/> (基于事务的策略)
集合缓存
<!-- 集合缓存[集合缓存的元素对象,也加加入二级缓存] -->
<collection-cache
usage="read-write" collection="cn.loaderman.b_second_cache.Dept.emps"/>
查询缓存
list() 默认情况只会放入缓存,不会从一级缓存中取!
使用查询缓存,可以让list()查询从二级缓存中取!
Hibernate.cfg.xml
<!--****************** 【二级缓存配置】****************** --> <!-- a. 开启二级缓存 --> <property name="hibernate.cache.use_second_level_cache">true</property> <!-- b. 指定使用哪一个缓存框架(默认提供的) --> <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property> <!-- 开启查询缓存 --> <property name="hibernate.cache.use_query_cache">true</property> <!-- c. 指定哪一些类,需要加入二级缓存 --> <class-cache usage="read-write" class="loaderman.b_second_cache.Dept"/> <class-cache usage="read-only" class="loaderman.b_second_cache.Employee"/> <!-- 集合缓存[集合缓存的元素对象,也加加入二级缓存] --> <collection-cache usage="read-write" collection="loaderman.b_second_cache.Dept.emps"/>
package loaderman.b_second_cache; import org.hibernate.Query; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; import org.junit.Test; public class App { private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(Dept.class) .addClass(Employee.class) // 测试时候使用 .buildSessionFactory(); } // 1. 测试二级缓存的使用 // 没有/有用 二级缓存 @Test public void testCache() { Session session1 = sf.openSession(); session1.beginTransaction(); // a. 查询一次 Dept dept = (Dept) session1.get(Dept.class, 10); dept.getEmps().size();// 集合 session1.getTransaction().commit(); session1.close(); System.out.println("------"); // 第二个session Session session2 = sf.openSession(); session2.beginTransaction(); // a. 查询一次 dept = (Dept) session2.get(Dept.class, 10); // 二级缓存配置好; 这里不查询数据库 dept.getEmps().size(); session2.getTransaction().commit(); session2.close(); } @Test public void listCache() { Session session1 = sf.openSession(); session1.beginTransaction(); // HQL查询 【setCacheable 指定从二级缓存找,或者是放入二级缓存】 Query q = session1.createQuery("from Dept").setCacheable(true); System.out.println(q.list()); session1.getTransaction().commit(); session1.close(); Session session2 = sf.openSession(); session2.beginTransaction(); q = session2.createQuery("from Dept").setCacheable(true); System.out.println(q.list()); // 不查询数据库: 需要开启查询缓存 session2.getTransaction().commit(); session2.close(); } }
package loaderman.b_second_cache; import java.util.HashSet; import java.util.Set; public class Dept { private int deptId; private String deptName; // 【一对多】 部门对应的多个员工 private Set<Employee> emps = new HashSet<Employee>(); public Dept(int deptId, String deptName) { super(); this.deptId = deptId; this.deptName = deptName; } public Dept() { super(); } public int getDeptId() { return deptId; } public void setDeptId(int deptId) { this.deptId = deptId; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } public Set<Employee> getEmps() { return emps; } public void setEmps(Set<Employee> emps) { this.emps = emps; } @Override public String toString() { return "Dept [deptId=" + deptId + ", deptName=" + deptName + "]"; } }
<?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="loaderman.b_second_cache"> <class name="Dept" table="t_dept" > <id name="deptId"> <generator class="native"></generator> </id> <property name="deptName" length="20"></property> <set name="emps"> <key column="dept_id"></key> <one-to-many class="Employee"/> </set> </class> <!-- 存放sql语句 --> <query name="getAllDept"> <![CDATA[ from Dept d where deptId < ? ]]> </query> </hibernate-mapping>
package loaderman.b_second_cache; public class Employee { private int empId; private String empName; private double salary; // 【多对一】员工与部门 private Dept dept;; public int getEmpId() { return empId; } public void setEmpId(int empId) { this.empId = empId; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } }
<?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="loaderman.b_second_cache"> <class name="loaderman.b_second_cache.Employee" table="t_employee"> <id name="empId"> <generator class="native"></generator> </id> <property name="empName" length="20"></property> <property name="salary" type="double"></property> <many-to-one name="dept" column="dept_id" class="Dept"></many-to-one> </class> </hibernate-mapping>