温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

(20)Hibernate二级缓存

发布时间:2020-08-06 03:24:19 来源:网络 阅读:515 作者:lsieun 栏目:数据库


1、二级缓存的知识

Hibernate提供的缓存:有一级缓存二级缓存。 目的是为了减少对数据库的访问次数,提升程序执行效率!


一级缓存:基于Session的缓存,缓存内容只在当前session有效,session关闭,缓存内容失效!

特点:作用范围较小! 缓存的时间短。缓存效果不明显。


二级缓存

Hibernate提供了基于应用程序级别的缓存, 可以跨多个session,即不同的session都可以访问缓存数据。 这个缓存也叫二级缓存。

Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可;不想用,直接移除,不影响代码。

如果用户觉得hibernate提供的框架不好用,可以换其他的缓存框架或自己实现缓存框架都可以。


下面的配置位于%hibernate%/project/etc/hibernate.properties中

########################## ### Second-level Cache ### ########################## ## disable the second-level cache 二级缓存默认不开启,需要手动开启 #hibernate.cache.use_second_level_cache false ## enable the query cache #hibernate.cache.use_query_cache true 开启查询缓存 ## choose a cache implementation 二级缓存框架的实现 #hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider #hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider #hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider #hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider #hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider


缓存的并发策略

<class-cache usage="read-only"/>     放入二级缓存的对象,只读;  <class-cache usage="nonstrict-read-write"/>  非严格的读写 <class-cache usage="read-write"/>    读写; 放入二级缓存的对象可以读、写; <class-cache usage="transactional"/>   (基于事务的策略)


2、使用二级缓存

二级缓存,使用步骤

    1)开启二级缓存

<property name="hibernate.cache.use_second_level_cache">true</property>

    2)指定缓存框架

<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>

    3)指定那些类加入二级缓存

<!-- 指定哪一些类,需要加入二级缓存 --> <class-cache usage="read-write" class="com.rk.hibernate.cache.Department"/> <class-cache usage="read-write" class="com.rk.hibernate.cache.Employee"/> <!-- 集合缓存[集合缓存的元素对象,也加加入二级缓存] --> <collection-cache usage="read-write" collection="com.rk.hibernate.cache.Department.emps"/>

    4)测试二级缓存!


示例代码和配置

hibernate.cfg.xml

<!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节点代表一个数据库 -->     <session-factory>         <!-- 1. 数据库连接配置 -->         <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>         <property name="hibernate.connection.url">jdbc:mysql:///test</property>         <property name="hibernate.connection.username">root</property>         <property name="hibernate.connection.password">root</property>	<!-- 	数据库方言配置, hibernate在运行的时候,会根据不同的方言生成符合当前数据库语法的sql	 -->         <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>                  <!-- 2. 其他相关配置 -->	<!-- 2.1 显示hibernate在运行时候执行的sql语句 -->	<property name="hibernate.show_sql">true</property>	<!-- 2.2 格式化sql -->	<property name="hibernate.format_sql">false</property>	<!-- 2.3 自动建表  -->	<property name="hibernate.hbm2ddl.auto">update</property>	<!--****************** 【二级缓存配置】****************** -->	<!-- 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="com.rk.hibernate.cache.Department"/>	<class-cache usage="read-write" class="com.rk.hibernate.cache.Employee"/>	<!-- 集合缓存[集合缓存的元素对象,也加加入二级缓存] -->	<collection-cache usage="read-write" collection="com.rk.hibernate.cache.Department.emps"/>     </session-factory> </hibernate-configuration>

Department.java

package com.rk.hibernate.cache; import java.util.Set; public class Department {	private int deptId;	private String deptName;	private Set<Employee> emps;	private int version;	public int getVersion()	{	return version;	}	public void setVersion(int version)	{	this.version = version;	}	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 "Department [deptId=" + deptId + ", deptName=" + deptName + "]";	} }

Department.hbm.xml

<?xml version="1.0" encoding="UTF-8"?> <!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.rk.hibernate.cache" auto-import="true">	<class name="Department" table="T_Department">	<!-- <cache usage="read-only"/> -->	<id name="deptId" column="id">	<generator class="native"></generator>	</id>	<version name="version" column="dept_version"></version>	<property name="deptName" column="name" type="string"></property>	<set name="emps" table="T_Employee">	<!-- <cache usage="read-only"/> -->	<key column="deptId"></key>	<one-to-many class="Employee"/>	</set>	</class> </hibernate-mapping> 

Employee.java

package com.rk.hibernate.cache; public class Employee {	private int empId;	private String empName;	private int salary;	private Department dept;	private int version;	public int getVersion()	{	return version;	}	public void setVersion(int version)	{	this.version = version;	}	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 int getSalary()	{	return salary;	}	public void setSalary(int salary)	{	this.salary = salary;	}	public Department getDept()	{	return dept;	}	public void setDept(Department dept)	{	this.dept = dept;	}	@Override	public String toString()	{	return "Employee [empId=" + empId + ", empName=" + empName + ", salary=" + salary + "]";	} }

Employee.hbm.xml

<?xml version="1.0" encoding="UTF-8"?> <!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.rk.hibernate.cache" auto-import="true">	<class name="Employee" table="T_Employee">	<!-- <cache usage="read-only"/> -->	<id name="empId" column="id">	<generator class="native"></generator>	</id>	<version name="version" column="emp_version"></version>	<property name="empName" column="name" type="string"></property>	<property name="salary" column="salary" type="int"></property>	<many-to-one name="dept" column="deptId" class="Department"></many-to-one>	</class> </hibernate-mapping>

App.java

package com.rk.hibernate.cache; import java.util.Iterator; import java.util.List; import java.util.Set; import org.hibernate.Query; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.Test; public class App {	private static SessionFactory sf;	static	{	sf = new Configuration()	.configure()	.addClass(Department.class)	.addClass(Employee.class)	.buildSessionFactory();	}	// 1. 测试二级缓存的使用	//思路:sesion本身提供了一级缓存,它是mandatory,不能关闭	//二级缓存,是optional,通过配置文件可以开启,可以关闭。	//如果不开启二级缓存,两个session查询同一个id的数据,会发送两个SQL语句	//如果开启二级缓存,两个session查询同一个id的数据,会发送一条SQL语句	//通过开启和关闭二级缓存,来查看执行的SQL数目	@Test	public void testSecondLevelCache()	{	//第1次查询,第一个session	Session session1 = sf.openSession();	session1.beginTransaction();	Department dept1 = (Department) session1.get(Department.class, 3);	Set<Employee> emps1 = dept1.getEmps();	System.out.println(dept1);	System.out.println(emps1);	session1.getTransaction().commit();	session1.close();	System.out.println("-------------------------------");	//第2次查询,第二个session	Session session2 = sf.openSession();	session2.beginTransaction();	Department dept2 = (Department) session2.get(Department.class, 3);	Set<Employee> emps2 = dept2.getEmps();	System.out.println(dept2);	System.out.println(emps2);	session2.getTransaction().commit();	session2.close();	}	@Test	public void testQueryCache()	{	// 第1次查询,第一个session	Session session1 = sf.openSession();	session1.beginTransaction();	// HQL查询  【setCacheable  指定从二级缓存找,或者是放入二级缓存】	Query q1 = session1.createQuery("from Department").setCacheable(true);	List<Department> list1 = q1.list();	System.out.println(list1);	session1.getTransaction().commit();	session1.close();	System.out.println("-------------------------------");	// 第2次查询,第二个session	Session session2 = sf.openSession();	session2.beginTransaction();	// HQL查询  【setCacheable  指定从二级缓存找,或者是放入二级缓存】	Query q2 = session2.createQuery("from Department").setCacheable(true);	List<Department> list2 = q2.list();	System.out.println(list2);	session2.getTransaction().commit();	session2.close();	} }


当我们开启二级缓存后,例如在上面的testSecondLevelCache()方法中,第一次从Session读取数据后,会存储在二级缓存上;第二次打开Session,程序再进行相同查询,就不需要再发送SQL语句,因为它会从二级缓存中读取数据。


有一点需要注意如果二级缓存中没有数据,第一次开启Session读取数据,并调用session.clear()方法,再读取数据,会发送两次SQL语句


@Test	public void test1()	{	// 第1次查询,第一个session	Session session1 = sf.openSession();	session1.beginTransaction();	Department dept1 = (Department) session1.get(Department.class, 2);	System.out.println(dept1);	System.out.println(dept1.getEmps());	session1.clear();	dept1 = (Department) session1.get(Department.class, 2);	System.out.println(dept1);	System.out.println(dept1.getEmps());	session1.getTransaction().commit();	session1.close();	}

结果如下:

Hibernate: select department0_.id as id0_0_, department0_.dept_version as dept2_0_0_, department0_.name as name0_0_ from T_Department department0_ where department0_.id=? Department [deptId=2, deptName=woqu] Hibernate: select emps0_.deptId as deptId0_1_, emps0_.id as id1_, emps0_.id as id1_0_, emps0_.emp_version as emp2_1_0_, emps0_.name as name1_0_, emps0_.salary as salary1_0_, emps0_.deptId as deptId1_0_ from T_Employee emps0_ where emps0_.deptId=? [Employee [empId=3, empName=TO_T_, salary=4]] Hibernate: select department0_.id as id0_0_, department0_.dept_version as dept2_0_0_, department0_.name as name0_0_ from T_Department department0_ where department0_.id=? Department [deptId=2, deptName=woqu] Hibernate: select emps0_.deptId as deptId0_1_, emps0_.id as id1_, emps0_.id as id1_0_, emps0_.emp_version as emp2_1_0_, emps0_.name as name1_0_, emps0_.salary as salary1_0_, emps0_.deptId as deptId1_0_ from T_Employee emps0_ where emps0_.deptId=? [Employee [empId=3, empName=TO_T_, salary=4]]


如果二级缓存中已经存在数据,第二次开启Session,调用session.clear(),再读取数据,并不会发送SQL语句。

@Test	public void test1()	{	Session session2 = sf.openSession();	session2.beginTransaction();	Department dept2 = (Department) session2.get(Department.class, 2);	System.out.println(dept2);	System.out.println(dept2.getEmps());	session2.getTransaction().commit();	session2.close();	System.out.println("-------------------------------");	// 第1次查询,第一个session	Session session1 = sf.openSession();	session1.beginTransaction();	Department dept1 = (Department) session1.get(Department.class, 2);	System.out.println(dept1);	System.out.println(dept1.getEmps());	session1.clear();	dept1 = (Department) session1.get(Department.class, 2);	System.out.println(dept1);	System.out.println(dept1.getEmps());	session1.getTransaction().commit();	session1.close();	System.out.println("-------------------------------");	}

结果如下:

Hibernate: select department0_.id as id0_0_, department0_.dept_version as dept2_0_0_, department0_.name as name0_0_ from T_Department department0_ where department0_.id=? Department [deptId=2, deptName=woqu] Hibernate: select emps0_.deptId as deptId0_1_, emps0_.id as id1_, emps0_.id as id1_0_, emps0_.emp_version as emp2_1_0_, emps0_.name as name1_0_, emps0_.salary as salary1_0_, emps0_.deptId as deptId1_0_ from T_Employee emps0_ where emps0_.deptId=? [Employee [empId=3, empName=TO_T_, salary=4]] ------------------------------- Department [deptId=2, deptName=woqu] [Employee [empId=3, empName=TO_T_, salary=4]] Department [deptId=2, deptName=woqu] [Employee [empId=3, empName=TO_T_, salary=4]] -------------------------------









向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI