溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

(20)Hibernate二級(jí)緩存

發(fā)布時(shí)間:2020-08-06 03:24:19 來(lái)源:網(wǎng)絡(luò) 閱讀:457 作者:lsieun 欄目:數(shù)據(jù)庫(kù)


1、二級(jí)緩存的知識(shí)

Hibernate提供的緩存:有一級(jí)緩存、二級(jí)緩存。 目的是為了減少對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)次數(shù),提升程序執(zhí)行效率!


一級(jí)緩存:基于Session的緩存,緩存內(nèi)容只在當(dāng)前session有效,session關(guān)閉,緩存內(nèi)容失效!

特點(diǎn):作用范圍較小! 緩存的時(shí)間短。緩存效果不明顯。


二級(jí)緩存

Hibernate提供了基于應(yīng)用程序級(jí)別的緩存, 可以跨多個(gè)session,即不同的session都可以訪問(wèn)緩存數(shù)據(jù)。 這個(gè)緩存也叫二級(jí)緩存。

Hibernate提供的二級(jí)緩存有默認(rèn)的實(shí)現(xiàn),且是一種可插配的緩存框架!如果用戶想用二級(jí)緩存,只需要在hibernate.cfg.xml中配置即可;不想用,直接移除,不影響代碼。

如果用戶覺得hibernate提供的框架不好用,可以換其他的緩存框架或自己實(shí)現(xiàn)緩存框架都可以。


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

##########################
### Second-level Cache ###
##########################

## disable the second-level cache 二級(jí)緩存默認(rèn)不開啟,需要手動(dòng)開啟
#hibernate.cache.use_second_level_cache false

## enable the query cache
#hibernate.cache.use_query_cache true 開啟查詢緩存

## choose a cache implementation 二級(jí)緩存框架的實(shí)現(xiàn)
#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


緩存的并發(fā)策略

<class-cache usage="read-only"/>     放入二級(jí)緩存的對(duì)象,只讀; 
<class-cache usage="nonstrict-read-write"/>  非嚴(yán)格的讀寫
<class-cache usage="read-write"/>    讀寫; 放入二級(jí)緩存的對(duì)象可以讀、寫;
<class-cache usage="transactional"/>   (基于事務(wù)的策略)


2、使用二級(jí)緩存

二級(jí)緩存,使用步驟

    1)開啟二級(jí)緩存

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

    2)指定緩存框架

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

    3)指定那些類加入二級(jí)緩存

<!-- 指定哪一些類,需要加入二級(jí)緩存 -->
<class-cache usage="read-write" class="com.rk.hibernate.cache.Department"/>
<class-cache usage="read-write" class="com.rk.hibernate.cache.Employee"/>
<!-- 集合緩存[集合緩存的元素對(duì)象,也加加入二級(jí)緩存] -->
<collection-cache usage="read-write" collection="com.rk.hibernate.cache.Department.emps"/>

    4)測(cè)試二級(jí)緩存!


示例代碼和配置

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>
    <!-- 通常,一個(gè)session-factory節(jié)點(diǎn)代表一個(gè)數(shù)據(jù)庫(kù) -->
    <session-factory>
        <!-- 1. 數(shù)據(jù)庫(kù)連接配置 -->
        <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>
		<!-- 
			數(shù)據(jù)庫(kù)方言配置, hibernate在運(yùn)行的時(shí)候,會(huì)根據(jù)不同的方言生成符合當(dāng)前數(shù)據(jù)庫(kù)語(yǔ)法的sql
		 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        
        <!-- 2. 其他相關(guān)配置 -->
		<!-- 2.1 顯示hibernate在運(yùn)行時(shí)候執(zhí)行的sql語(yǔ)句 -->
		<property name="hibernate.show_sql">true</property>
		<!-- 2.2 格式化sql -->
		<property name="hibernate.format_sql">false</property>
		<!-- 2.3 自動(dòng)建表  -->
		<property name="hibernate.hbm2ddl.auto">update</property>
		

		<!--****************** 【二級(jí)緩存配置】****************** -->
		<!-- a. 開啟二級(jí)緩存 -->
		<property name="hibernate.cache.use_second_level_cache">true</property>
		<!-- b. 指定使用哪一個(gè)緩存框架(默認(rèn)提供的) -->
		<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
		<!-- 開啟查詢緩存 -->
		<property name="hibernate.cache.use_query_cache">true</property>
		<!-- c. 指定哪一些類,需要加入二級(jí)緩存 -->
		<class-cache usage="read-write" class="com.rk.hibernate.cache.Department"/>
		<class-cache usage="read-write" class="com.rk.hibernate.cache.Employee"/>
		<!-- 集合緩存[集合緩存的元素對(duì)象,也加加入二級(jí)緩存] -->
		<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. 測(cè)試二級(jí)緩存的使用
	//思路:sesion本身提供了一級(jí)緩存,它是mandatory,不能關(guān)閉
	//二級(jí)緩存,是optional,通過(guò)配置文件可以開啟,可以關(guān)閉。
	//如果不開啟二級(jí)緩存,兩個(gè)session查詢同一個(gè)id的數(shù)據(jù),會(huì)發(fā)送兩個(gè)SQL語(yǔ)句
	//如果開啟二級(jí)緩存,兩個(gè)session查詢同一個(gè)id的數(shù)據(jù),會(huì)發(fā)送一條SQL語(yǔ)句
	//通過(guò)開啟和關(guān)閉二級(jí)緩存,來(lái)查看執(zhí)行的SQL數(shù)目
	@Test
	public void testSecondLevelCache()
	{
		//第1次查詢,第一個(gè)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次查詢,第二個(gè)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次查詢,第一個(gè)session
		Session session1 = sf.openSession();
		session1.beginTransaction();
		// HQL查詢  【setCacheable  指定從二級(jí)緩存找,或者是放入二級(jí)緩存】
		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次查詢,第二個(gè)session
		Session session2 = sf.openSession();
		session2.beginTransaction();
		// HQL查詢  【setCacheable  指定從二級(jí)緩存找,或者是放入二級(jí)緩存】
		Query q2 = session2.createQuery("from Department").setCacheable(true);
		List<Department> list2 = q2.list();
		System.out.println(list2);
		session2.getTransaction().commit();
		session2.close();
	}
	
}


當(dāng)我們開啟二級(jí)緩存后,例如在上面的testSecondLevelCache()方法中,第一次從Session讀取數(shù)據(jù)后,會(huì)存儲(chǔ)在二級(jí)緩存上;第二次打開Session,程序再進(jìn)行相同查詢,就不需要再發(fā)送SQL語(yǔ)句,因?yàn)樗鼤?huì)從二級(jí)緩存中讀取數(shù)據(jù)。


有一點(diǎn)需要注意如果二級(jí)緩存中沒(méi)有數(shù)據(jù),第一次開啟Session讀取數(shù)據(jù),并調(diào)用session.clear()方法,再讀取數(shù)據(jù),會(huì)發(fā)送兩次SQL語(yǔ)句。


	@Test
	public void test1()
	{
		// 第1次查詢,第一個(gè)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();

	}

結(jié)果如下:

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]]


如果二級(jí)緩存中已經(jīng)存在數(shù)據(jù),第二次開啟Session,調(diào)用session.clear(),再讀取數(shù)據(jù),并不會(huì)發(fā)送SQL語(yǔ)句。

	@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次查詢,第一個(gè)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("-------------------------------");
	}

結(jié)果如下:

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問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI