昆明java培训
达内昆明广州春城路

18487146383

热门课程

Hibernate中的二级缓存

  • 时间:2016-10-24
  • 发布:昆明Java培训
  • 来源:达内新闻

昆明达内Java培训的老师今天给大家讲Hibernate——二级缓存

一、Hibernate二级缓存

1.Hibernate二级缓存是SessionFactory级别的缓存。

2.二级缓存分为两类:

(1)Hibernate内置二级缓存

(2)外置缓存,可配置的,可插拨的,外置缓存中的数据是数据库数据的复制。

3.二级缓存的并发访问策略

(1)两个并发的事务同时访问持久层的缓存的相同数据时,也有可能出现并发问题。

(2)二级缓存可以设定以下4中并发访问策略,每一种对应一种事务隔离级别。

非严格读写(Nonstrict-read-write):不保证缓存与数据库中数据的一致性。对应Read UnCommited事务隔离级别。

读写型(Read-write):提供Read Commited级别的事务隔离级别。

事务型(Transactional):对应Repeatable Read级别的事务隔离级别。

只读型(Read-Only):提供Serializable级别的数据隔离级别。

4.Hibernate二级缓存是进程或集群范围内的缓存。是可配置的的插件。这里以Ehcache为例。不支持事务型的并发访问策略。

5.配置Ehcache

(1)添加Jar包

(2)在Hibernate配置文件中启用二级缓存并指定适配的缓存适配器。

在<session-factory>元素内添加:

<property ame="cache.use_second_level_cache">true</property>

<property ame="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

(3)在Hibernate配置文件中配置需要使用二级缓存的持久化类,并设置它的二级缓存的并发访问策略。如:

<class-cache class="com.solverpeng.hql.Department" usage="read-write"/>

需要注意的是:<session-factory>元素内子元素的顺序:property*, mapping*, (class-cache|collection-cache)*, event*, listener*,class-cache元素必须位于mapping节点后。

(4)或者也可以在hbm文件中配置,如:

<hibernate-mapping>

<class name="com.solverpeng.hql.Employee" table="employee" schema="hibernate">

<cache usage="read-write"/>

<id name="empId" column="emp_id"/>

<property name="empName" column="emp_name"/>

<property name="salary" column="salary"/>

<many-to-one name="dept" class="com.solverpeng.hql.Department">

<column ame="dept_id_fk" not-null="true"/>

</many-to-one>

</class>

</hibernate-mapping>

6.测试Hibernate二级缓存

(1)查询单个对象缓存

@Test

public void testSecondCache() {

Employee o = (Employee) session.get(Employee.class, 6);

System.out.println(o);

transaction.commit();

session.close();

session = factory.openSession();

transaction = session.beginTransaction();

Employee o1 = (Employee) session.get(Employee.class, 6);

System.out.println(o1);

}

查询同一个对象两次,中间关闭Session再开启。

没有配置二级缓存:

Hibernate:

select

employee0_.emp_id as emp1_1_0_,

employee0_.emp_name as emp2_1_0_,

employee0_.salary as salary3_1_0_,

employee0_.dept_id_fk as dept4_1_0_

from

hibernate.employee employee0_

where

employee0_.emp_id=?

com.solverpeng.hql.Employee@40dd58f3

Hibernate:

select

employee0_.emp_id as emp1_1_0_,

employee0_.emp_name as emp2_1_0_,

employee0_.salary as salary3_1_0_,

employee0_.dept_id_fk as dept4_1_0_

from

hibernate.employee employee0_

where

employee0_.emp_id=?

com.solverpeng.hql.Employee@40dd58f3

结果:

发送了2条SQL语句。

配置二级缓存后(可以在Hibernate配置文件中配置,也可以在Employee hbm配置文件中配置):

Hibernate:

select

employee0_.emp_id as emp1_1_0_,

employee0_.emp_name as emp2_1_0_,

employee0_.salary as salary3_1_0_,

employee0_.dept_id_fk as dept4_1_0_

from

hibernate.employee employee0_

where

employee0_.emp_id=?

com.solverpeng.hql.Employee@40dd58f3

com.solverpeng.hql.Employee@40dd58f3

结果:

只发送了1条SQL语句。

(2)集合缓存

@Test

public void testCollectionSecondLevelCache() {

Department department = (Department) session.get(Department.class, 6);

System.out.println(department.getDeptName());

System.out.println(department.getEmps().size());

transaction.commit();

session.close();

session = factory.openSession();

transaction = session.beginTransaction();

Department department2 = (Department) session.get(Department.class, 6);

System.out.println(department2.getDeptName());

System.out.println(department2.getEmps().size());

}

在没有配置二级缓存的情况下:

Hibernate:

select

department0_.dept_id as dept1_0_0_,

department0_.dept_name as dept2_0_0_

from

hibernate.department department0_

where

department0_.dept_id=?

dept-aa

Hibernate:

select

emps0_.dept_id_fk as dept4_0_1_,

emps0_.emp_id as emp1_1_1_,

emps0_.emp_id as emp1_1_0_,

emps0_.emp_name as emp2_1_0_,

emps0_.salary as salary3_1_0_,

emps0_.dept_id_fk as dept4_1_0_

from

hibernate.employee emps0_

where

emps0_.dept_id_fk=?

3

Hibernate:

select

department0_.dept_id as dept1_0_0_,

department0_.dept_name as dept2_0_0_

from

hibernate.department department0_

where

department0_.dept_id=?

dept-aa

Hibernate:

select

emps0_.dept_id_fk as dept4_0_1_,

emps0_.emp_id as emp1_1_1_,

emps0_.emp_id as emp1_1_0_,

emps0_.emp_name as emp2_1_0_,

emps0_.salary as salary3_1_0_,

emps0_.dept_id_fk as dept4_1_0_

from

hibernate.employee emps0_

where

emps0_.dept_id_fk=?

3

结果:

查询了两次Department,两次Employee

只配置Department二级缓存:

<class-cache class="com.solverpeng.hql.Department" usage="read-write"/>

Hibernate:

select

department0_.dept_id as dept1_0_0_,

department0_.dept_name as dept2_0_0_

from

hibernate.department department0_

where

department0_.dept_id=?

dept-aa

Hibernate:

select

emps0_.dept_id_fk as dept4_0_1_,

emps0_.emp_id as emp1_1_1_,

emps0_.emp_id as emp1_1_0_,

emps0_.emp_name as emp2_1_0_,

emps0_.salary as salary3_1_0_,

emps0_.dept_id_fk as dept4_1_0_

from

hibernate.employee emps0_

where

emps0_.dept_id_fk=?

3

dept-aa

Hibernate:

select

emps0_.dept_id_fk as dept4_0_1_,

emps0_.emp_id as emp1_1_1_,

emps0_.emp_id as emp1_1_0_,

emps0_.emp_name as emp2_1_0_,

emps0_.salary as salary3_1_0_,

emps0_.dept_id_fk as dept4_1_0_

from

hibernate.employee emps0_

where

emps0_.dept_id_fk=?

3

结果:

只查询了一次Department,2次Employee。

说明:

开启Department二级缓存后,会对Department进行缓存,而与其关联的emps不会进行缓存。

配置Department二级缓存,同时配置关联的emps缓存。

<class-cache class="com.solverpeng.hql.Department" usage="read-write"/>

<collection-cache collection="com.solverpeng.hql.Department.emps" usage="read-write"/>

Hibernate:

select

department0_.dept_id as dept1_0_0_,

department0_.dept_name as dept2_0_0_

from

hibernate.department department0_

where

department0_.dept_id=?

dept-aa

Hibernate:

select

emps0_.dept_id_fk as dept4_0_1_,

emps0_.emp_id as emp1_1_1_,

emps0_.emp_id as emp1_1_0_,

emps0_.emp_name as emp2_1_0_,

emps0_.salary as salary3_1_0_,

emps0_.dept_id_fk as dept4_1_0_

from

hibernate.employee emps0_

where

emps0_.dept_id_fk=?

3

-----------------------------

dept-aa

Hibernate:

select

employee0_.emp_id as emp1_1_0_,

employee0_.emp_name as emp2_1_0_,

employee0_.salary as salary3_1_0_,

employee0_.dept_id_fk as dept4_1_0_

from

hibernate.employee employee0_

where

employee0_.emp_id=?

Hibernate:

select

employee0_.emp_id as emp1_1_0_,

employee0_.emp_name as emp2_1_0_,

employee0_.salary as salary3_1_0_,

employee0_.dept_id_fk as dept4_1_0_

from

hibernate.employee employee0_

where

employee0_.emp_id=?

Hibernate:

select

employee0_.emp_id as emp1_1_0_,

employee0_.emp_name as emp2_1_0_,

employee0_.salary as salary3_1_0_,

employee0_.dept_id_fk as dept4_1_0_

from

hibernate.employee employee0_

where

employee0_.emp_id=?

3

结果:

发送了更多的查询Employee的SQL。

说明:

开启集合的二级缓存后,此时会缓存集合中对象的id,而不会对集合中的对象进行缓存。若想缓存,需要关联的集合中的对象也开启二级缓存。如:

<class-cache class="com.solverpeng.hql.Department" usage="read-write"/>

<collection-cache collection="com.solverpeng.hql.Department.emps" usage="read-write"/>

<class-cache class="com.solverpeng.hql.Employee" usage="read-write"/>

Hibernate:

select

department0_.dept_id as dept1_0_0_,

department0_.dept_name as dept2_0_0_

from

hibernate.department department0_

where

department0_.dept_id=?

dept-aa

Hibernate:

select

emps0_.dept_id_fk as dept4_0_1_,

emps0_.emp_id as emp1_1_1_,

emps0_.emp_id as emp1_1_0_,

emps0_.emp_name as emp2_1_0_,

emps0_.salary as salary3_1_0_,

emps0_.dept_id_fk as dept4_1_0_

from

hibernate.employee emps0_

where

emps0_.dept_id_fk=?

3

-----------------------------

dept-aa

3

结果:

除Department外,关联的Employee也被缓存了。

(3)查询缓存(针对HQL、QBC)

在二级缓存开启的情况下,HQL、QBC也不能对查询进行缓存。

@Test

public void testQueryCache() {

Query query = session.createQuery("from Employee ");

List<Employee> list = query.list();

System.out.println(list.size());

List<Employee> emps2 = query.list();

System.out.println(emps2.size());

}

Hibernate:

select

employee0_.emp_id as emp1_1_,

employee0_.emp_name as emp2_1_,

employee0_.salary as salary3_1_,

employee0_.dept_id_fk as dept4_1_

from

hibernate.employee employee0_

12

Hibernate:

select

employee0_.emp_id as emp1_1_,

employee0_.emp_name as emp2_1_,

employee0_.salary as salary3_1_,

employee0_.dept_id_fk as dept4_1_

from

hibernate.employee employee0_

12

开启查询缓存:

在Hibernate配置文件中开启查询缓存

若想启用查询缓存的查询语句,需要调用Query或Criteria的setCacheable()方法。

查询缓存依赖于二级缓存

<property ame="hibernate.cache.use_query_cache">true</property>

@Test

public void testQueryCache() {

Query query = session.createQuery("from Employee ");

query.setCacheable(true);

List<Employee> list = query.list();

System.out.println(list.size());

List<Employee> emps2 = query.list();

System.out.println(emps2.size());

}

Hibernate:

select

employee0_.emp_id as emp1_1_,

employee0_.emp_name as emp2_1_,

employee0_.salary as salary3_1_,

employee0_.dept_id_fk as dept4_1_

from

hibernate.employee employee0_

12

12

(4)时间戳缓存区域:时间戳缓存区存放了对于查询结果相关的表进行插入、更新或删除操作的时间戳。Hibernate通过时间戳缓存区来判定被缓存的查询结果是否过期。

@Test

public void testTimStampCache() {

Query query = session.createQuery("from Employee ");

query.setCacheable(true);

List<Employee> list = query.list();

System.out.println(list.size());

Employee employee = (Employee) session.get(Employee.class, 6);

employee.setEmpName("emp@@");

List<Employee> emps2 = query.list();

System.out.println(emps2.size());

}

Hibernate:

select

employee0_.emp_id as emp1_1_,

employee0_.emp_name as emp2_1_,

employee0_.salary as salary3_1_,

employee0_.dept_id_fk as dept4_1_

from

hibernate.employee employee0_

12

Hibernate:

update

hibernate.employee

set

emp_name=?,

salary=?,

dept_id_fk=?

where

emp_id=?

Hibernate:

select

employee0_.emp_id as emp1_1_,

employee0_.emp_name as emp2_1_,

employee0_.salary as salary3_1_,

employee0_.dept_id_fk as dept4_1_

from

hibernate.employee employee0_

12

了解详情请登陆昆明达内Java培训官网(km.Java.tedu.cn)!

上一篇:Java培训:Spring之AOP
下一篇:Hibernate中的ehcache.xml

达内培训小米MIX 2尊享版工艺精湛

程序猿教你java的创建和销毁对象

昆明java培训-程序猿带你入门到精通

昆明达内-有趣的轻量级图像浏览器

选择城市和中心
贵州省

广西省

海南省