Hibernate缓存浅析
第一次用markdown写博客,小激动!!!
- 一级缓存
- 二级缓存
- 会话(session)级缓存
- 全局缓存
hibernate缓存的作用
-并不是指计算机或者内存的一二级缓存
-缓存的目的是为了降低应用程序对物理数据源访问的次数从而提高应用程序运行性能的一种策略
-使用缓存的目的是为了提升和优化hibernate的执行效率
hibernate缓存的一般工作原理
-在hibernate中查询数据时,会先检查缓存中是否存在,若存在则直接读取(称之为缓存命中)
-若不存在则直接再去数据库中读取并返回数据
一级缓存
一级缓存的特点
-用户不可关闭
-缓存生命周期与其对应的session相同
-再同一个session中对同一个对象多次查询仅会发出一次sql语句
-在不同的session进行查询会发出多次sql语句即不同的session对应不同的一级缓存
在同一session种执行两次查询
// 创建 hibernate 配置对象
Configuration configuration = new Configuration().configure();
// 创建服务注册对象
org.hibernate.service.ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
// 生成SessionFactory
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(serviceRegistry);
// 创建session
Session session = sessionFactory.getCurrentSession();
// 创建事务
Transaction transaction = session.beginTransaction();
StudentsPK pk = new StudentsPK();
pk.setId(789);
pk.setSid(456);
Students students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
我们可以看到hibernate框架只发出了一次sql语句
而打印了两次结果
在不同session中执行查询
// 创建 hibernate 配置对象
Configuration configuration = new Configuration().configure();
// 创建服务注册对象
org.hibernate.service.ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
// 生成SessionFactory
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(serviceRegistry);
// 创建session
Session session = sessionFactory.getCurrentSession();
// 创建事务
Transaction transaction = session.beginTransaction();
StudentsPK pk = new StudentsPK();
pk.setId(789);
pk.setSid(456);
Students students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
Session session2 = sessionFactory.openSession();
students = (Students) session2.get(Students.class, pk);
System.out.println(students.getSname());
在不同的session中我们进行查询可以看到输出了两次sql语句
证明不同的session用的不是同一个一级缓存
一级缓存的两个常用方法
-一级缓存无法取消,采用两个方法进行管理
-evict():用于将某个对象从一级缓存中删除
-clear():用于将一级缓存中所有对象清除
evict()的使用
// 创建 hibernate 配置对象
Configuration configuration = new Configuration().configure();
// 创建服务注册对象
org.hibernate.service.ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
// 生成SessionFactory
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(serviceRegistry);
// 创建session
Session session = sessionFactory.getCurrentSession();
// 创建事务
Transaction transaction = session.beginTransaction();
StudentsPK pk = new StudentsPK();
pk.setId(789);
pk.setSid(456);
Students students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
// 将对象删除
session.evict(students);
students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
我们可以在同一session中进行两次查询,因为中间有删除对象的操作所以发出了两次sql语句
clear()的使用
// 创建 hibernate 配置对象
Configuration configuration = new Configuration().configure();
// 创建服务注册对象
org.hibernate.service.ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
// 生成SessionFactory
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(serviceRegistry);
// 创建session
Session session = sessionFactory.getCurrentSession();
// 创建事务
Transaction transaction = session.beginTransaction();
StudentsPK pk = new StudentsPK();
pk.setId(789);
pk.setSid(456);
Students students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
// 将所有对象删除
session.clear();
students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
从控制台输出我们可以看到,同样执行了两次sql语句
hibernate二级缓存
-又称为“全局缓存”,“应用级缓存”
-每个session都可以访问其中的内容,即每个session都共用的缓存
-可取消、可自定义
二级缓存的配置步骤
导入相应的包
导入包的过程不赘述,在hibernate的jar里面就有,题主这里采用的是hibernate-4.3.5-final。缓存包路径为hibernate4.3.5\hibernate4.3.5\lib\optional\ehcache
在hibernate.cfg.xml配置文件中添加Provider类描述
-在配置文件中添加以下属性
-provider所在位置(已标出)
添加二级缓存的属性配置文件
-属性配置文件位置
-添加到project中
在需要被缓存的表所对应的映射文件中添加标签
代码验证二级缓存效果
-使用两个会话
Students students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
session = sessionFactory.openSession();
students = (Students) session.get(Students.class, pk);
System.out.println(students.getSname());
-从控制台输出可以看到仅发出了一次sql语句,说明二级缓存生效
cache标签介绍
<!-- 只读事务模式,效率高 -->
<cache usage="read-only"/>
<!-- 缓存除了PK以外其他延迟加载的属性,region="test"指定的属性是在acache.xml 配置专属缓存策略 -->
<cache usage="read-only" include="all" region="test"/>
< cache name="test" <!-- 标识为defaultCache表示该策略为默认策略 -->
maxElementsInMemory="10000" <!-- 表示缓存中允许创建的最大对象数-->
eternal="false" <!-- 表示缓存中的对象是否是永久的 -->
timeToIdleSeconds="120" <!-- 表示缓存数据的钝化时间 -->
timeToLiveSeconds="120" <!-- 表示缓存生存时间 -->
overflowToDisk="true" <!-- 表示缓存溢出后是否存储在硬盘上 -->
/>
二级缓存使用情景
-很少被修改的数据
-不是很重要的数据,允许偶尔出息并发的数据
-不会被并发访问的数据
-参考数据
-策略类数据
-缓存能提高检索效率,但会占用更多的资源
总结
一二级缓存对比
- | 一级缓存 | 二级缓存 |
---|---|---|
缓存范围 | 事务范围,每个事务拥有单独的一级缓存 | 应用范围,当前应用内所有事务共享 |
并发访问策略 | 无并发 | 必须提供适当的并发访问策略 |
数据过期策略 | 无数据过期策略 | 缓存对象的最大数目、最长时间、最长空闲时间 |
缓存的软件实现 | 框架内包含 | 第三方提供,可插拔 |
物理介质 | 内存 | 内存和硬盘 |
启动方式 | 默认启用,不可关闭 | 默认不启用,选择性开启 |
缓存的作用
-提供检索效率但同时也会增加资源的占用和消耗