1)Hibernate一级缓存
session即为Hibernate的一级缓存,其中缓存的数据随着session的关闭而消失。因而从缓存角度讲session作为一级缓存对性能的提升不大。(当然session的主要作用不是作为缓存,而是用来管理对象,持久化状态的对象的变化可以更新到数据库中)
factory = new Configuration().configure().buildSessionFactory();
session = factory.openSession();
Department department = (Department) session.load(Department.class, 2l);
System.out.println(department.getName());
session.close();
session = factory.openSession();
Department department2 = (Department) session.load(Department.class, 2l);
System.out.println(department2.getName());
session.close();
结果为:
Hibernate: select department0_.id as id1_3_0_, department0_.name as name2_3_0_ from t_department department0_ where department0_.id=?
develope
Hibernate: select department0_.id as id1_3_0_, department0_.name as name2_3_0_ from t_department department0_ where department0_.id=?
develope
说明session关闭后其中缓存的数据也消失了,所以虽然第二次查询的是同样的数据,但是还是去查询数据库了。
2)配置二级缓存
1. 导入jar
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.3.6.Final</version>
</dependency>
2. 修改hibernate.cfg.xml文件
基础配置:
<!-- 表示是否开启二级缓存,默认为false -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 指定使用的二级缓存 -->
<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>
<!-- 指定EHCache的配置文件 -->
<property name="hibernate.cache.provider_configuration_file_resource_path">
ehcache.xml
</property>
说明哪些类需要使用缓存
<class-cache usage="read-write" class="cn.com.cpf.pojo.Department"/>
3.ehcache.xml中配置
<ehcache>
<!--如果缓存中的对象存储超过指定的缓存数量的对象存储的磁盘地址(文件夹)-->
<diskStore path="D:/ehcache"/>
<!-- 默认cache:如果没有对应的特定区域的缓存,就使用默认缓存 -->
<defaultCache maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="false"/> //开启则表示如果超过缓存数量则写入到硬盘中
</cache>
</ehcache>
4. 执行如上代码,结果为:
Hibernate: select department0_.id as id1_3_0_, department0_.name as name2_3_0_ from t_department department0_ where department0_.id=?
develope
develope
只查询了一次数据库,说明二级缓存已经起作用
3)具有如下特征的数据适合放入二级缓存中
1.很少被修改的数据
2.不是很重要的数据,允许偶尔出现并发的数据
3.常量数据
4) 具有如下特征的数据不适合放入二级缓存中
1.经常被修改的数据
2.非常重要(如财务数据),决不允许出现并发操作的数据
5)Hibernate中 缓存分类
1.类缓存
1>配置方法
hibernate.cfg.xml中
<class-cache usage="read-write" class="cn.com.cpf.pojo.Department"/>
2>工作原理
使用一个Map将对象id作为key,对象作为value。查询的时候现根据id查找一级缓存,一级缓存中没有则查找二级缓存,也没有则查询数据库
3>注意
因为是根据id来查找的,所以通过get、load这种根据id查找的方式才可以使用缓存,使用hql这种方式一定会查数据库
2.集合缓存
1>配置方法
hibernate.cfg.xml中
<class-cache usage="read-write" class="cn.com.cpf.pojo.Employee"/>
<collection-cache usage="read-write" collection="cn.com.cpf.pojo.Department.employees"/>
必须将集合属性和对应类全被指定才行,少一个都不会使用二级缓存
2>实例
pojo:
public class Department {
private Long id;
private String name;
private Set<Employee> employees = new HashSet<Employee>();
..............
}
Department.hbm.xml
<class name="cn.com.cpf.pojo.Department" table="t_department" lazy="true">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="employees" inverse="false" lazy="true">
<key column="departmentId"/>
<one-to-many class="cn.com.cpf.pojo.Employee" />
</set>
</class>
hibernate.cfg.xml
<?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/test
</property>
<property name="connection.username">root</property>
<property name="connection.password">12345</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="connection.isolation">2</property>
<!-- 表示是否开启二级缓存,默认为false -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 指定使用的二级缓存 -->
<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>
<!-- 指定EHCache的配置文件 -->
<property name="hibernate.cache.provider_configuration_file_resource_path">
ehcache.xml
</property>
<property name="show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.max_size">2</property>
<property name="hibernate.c3p0.min_size">2</property>
<property name="hibernate.c3p0.timeout">5000</property>
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.validate">false</property>
<mapping resource="cn/com/cpf/pojo/Department.hbm.xml"/>
<mapping resource="cn/com/cpf/pojo/Employee.hbm.xml"/>
<class-cache usage="read-write" class="cn.com.cpf.pojo.Department"/>
<class-cache usage="read-write" class="cn.com.cpf.pojo.Employee"/>
<collection-cache usage="read-write" collection="cn.com.cpf.pojo.Department.employees"/>
</session-factory>
</hibernate-configuration>
测试代码:
factory = new Configuration().configure().buildSessionFactory();
session = factory.openSession();
Department department = (Department) session.load(Department.class, 2l);
System.out.println(department.getName());
System.out.println(department.getEmployees());
session.close();
session = factory.openSession();
Department department2 = (Department) session.load(Department.class, 2l);
System.out.println(department.getName());
System.out.println(department2.getEmployees());
session.close();
结果为:
Hibernate: select department0_.id as id1_3_0_, department0_.name as name2_3_0_ from t_department department0_ where department0_.id=?
develope
Hibernate: select employees0_.departmentId as departme3_3_0_, employees0_.id as id1_4_0_, employees0_.id as id1_4_1_, employees0_.name as name2_4_1_, employees0_.departmentId as departme3_4_1_ from t_employee employees0_ where employees0_.departmentId=?
[cn.com.cpf.pojo.Employee@7ccc8469, cn.com.cpf.pojo.Employee@57094981]
develope
[cn.com.cpf.pojo.Employee@7e0e03d0, cn.com.cpf.pojo.Employee@4a1c8d57]
第二次查询时候没有查询数据库,说明二级缓存生效了
如果在hibernate.cfg.xml中去掉对Employee类使用二级缓存的声明,即
<class-cache usage="read-write" class="cn.com.cpf.pojo.Department"/>
<collection-cache usage="read-write" collection="cn.com.cpf.pojo.Department.employees"/>
再执行测试代码,结果为:
Hibernate: select department0_.id as id1_3_0_, department0_.name as name2_3_0_ from t_department department0_ where department0_.id=?
develope
Hibernate: select employees0_.departmentId as departme3_3_0_, employees0_.id as id1_4_0_, employees0_.id as id1_4_1_, employees0_.name as name2_4_1_, employees0_.departmentId as departme3_4_1_ from t_employee employees0_ where employees0_.departmentId=?
[cn.com.cpf.pojo.Employee@54be8c3e, cn.com.cpf.pojo.Employee@29e965e9]
develope
Hibernate: select employee0_.id as id1_4_0_, employee0_.name as name2_4_0_, employee0_.departmentId as departme3_4_0_ from t_employee employee0_ where employee0_.id=?
Hibernate: select employee0_.id as id1_4_0_, employee0_.name as name2_4_0_, employee0_.departmentId as departme3_4_0_ from t_employee employee0_ where employee0_.id=?
[cn.com.cpf.pojo.Employee@58dcdffc, cn.com.cpf.pojo.Employee@fbb8694]
可以看出在第二次访问类中集合的时候仍然访问了数据库,而且针对每一个对象都根据id访问了一次数据库。
原因:仅对collection属性做了缓存,那么Hibernate二级缓存只会缓存collection中的id,第二次查询的时候,从缓存里面仅仅能查询出来id,所以就根据这个id分别查询了。
3. 查询缓存
1>说明:不管是类缓存还是集合缓存,都是缓存的id,所以无法使用hql。要使用查询缓存,那么就需要使用查询语句作为key,对象作为value保存
2>配置
在hibernate.cfg.xml中添加配置
<property name="cache.use_query_cache">true</property>
3>使用
factory = new Configuration().configure().buildSessionFactory();
session = factory.openSession();
List<Department> departments = (List<Department>) session//
.createQuery("FROM Department where id<3")//
.setCacheable(true)//
.list();
session.close();
session = factory.openSession();
List<Department> departments2 = (List<Department>) session//
.createQuery("FROM Department where id<3")//
.setCacheable(true)//
.list();
session.close();
结果为:
Hibernate: select department0_.id as id1_3_, department0_.name as name2_3_ from t_department department0_ where department0_.id<3
只有一条sql,说明二级缓存已经起作用了
4>注意
在使用hql查询的时候,需要调用setCacheable方法,并在配置文件中设置了使用查询缓存才会使用缓存
Query或Criteria接口查询时设置其setCacheable(true):
默认的如果不在程序中显示的执行查询缓存声明操作,Hibernate是不会对查询的list进行缓存的。