1. 二级缓存
Hibernate中的二级缓存,二级缓存是属于SessionFactory级别的缓存机制。第一级别的缓存是Session级别的缓存,是属于事务范围的缓存,由Hibernate管理,一般无需进行干预。第二级别的缓存是SessionFactory级别的缓存,是属于进程范围的缓存。
1.1 二级缓存分类:
内置缓存:Hibernate自带的,不可卸载,通常在Hibernate的初始化阶段,Hibernate会把映射元数据和预定义的SQL语句放置到SessionFactory的缓存中。该内置缓存是只读的。
外置缓存:通常说的二级缓存也就是外置缓存,在默认情况下SessionFactory不会启用这个缓存插件,外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存或者硬盘。
-
hibernate 二级缓存的结构:
图片.png
1.2 二级缓存并发访问策略
策略 | 使用场景 |
---|---|
transactional(事务型) | 提供Repeatable Read事务隔离级别;适用经常被读,很少修改的数据;可以防止脏读和不可重复读的并发问题;缓存支持事务,发生异常的时候,缓存也能够回滚 |
read-write(读写型) | 提供Read Committed事务隔离级别;在非集群的环境中适用;适用经常被读,很少修改的数据;可以防止脏读;更新缓存的时候会锁定缓存中的数据 |
nonstrict-read-write(非严格读写型) | 适用极少被修改,偶尔允许脏读的数据(两个事务同时修改数据的情况很少见);不保证缓存和数据库中数据的一致性;为缓存数据设置很短的过期时间,从而尽量避免脏读;不锁定缓存中的数据 |
read-only(只读型) | 适用从来不会被修改的数据(如参考数据);在此模式下,如果对数据进行更新操作,会有异常;事务隔离级别低,并发性能高;在集群环境中也能完美运作 |
分析总结,二级缓存应用场景:
适合放入二级缓存中数据
- 很少被修改
- 不是很重要的数据,允许出现偶尔的并发问题
不使用二级缓存数据
- 经常被修改
- 财务数据,绝对不允许出现并发问题
- 与其他应用数据共享的数据
1.3 hibernate支持的缓存插件(缓存提供的供应商)
• EHCache:可作为进程范围内的缓存,存放数据的物理介质可以是内存或硬盘,对Hibernate的查询缓存提供了支持
• OpenSymphony`:可作为进程范围内的缓存,存放数据的物理介质可以是内存或硬盘,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持
• OSCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持
• SwarmCache:可作为集群范围内的缓存,但不支持Hibernate的查询缓存
• JBossCache:可作为集群范围内的缓存,支持Hibernate的查询缓存
• 缓存插件 并发策略支持如下图
1.4 EHCache配置步骤
- 导包 配置POM 文件,引入 ehcache 插件
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.2.12.Final</version>
</dependency>
- 核心配置文件中 开启二级缓存
<!--开启二级缓存-->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!--配置 二级缓存的提供商-->
<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>
- 开启类缓存
<class name="com.xingxue.day5.hibernate.domain.UserModel" table="t_user">
<!-- 开启二级缓存的类缓存 -->
<cache usage="read-write"/>
注意:一级缓存对象的修改会影响二级缓存
- 开启集合缓存
<set name="userModels" table="t_user_role" inverse="true">
<!--开启当前的集合缓存-->
<cache usage="read-write"/>
- 查询缓存:缓存的查询数据,要求 sql 以及参数要一模一样。
<!--开启查询缓存,一定是在二级缓存的基础上才能使用-->
<property name="hibernate.cache.use_query_cache">true</property>
List<RoleModel> rs = session.createQuery("select r from RoleModel r where r.id = 1 and 1 = 1")
//查询的数据放入查询缓存中
// 开启查询缓存
.setCacheable(true)
.list();
session.close();
Session session1 = factory.openSession();
List<RoleModel> rs2 = session1.createQuery("from RoleModel where id = 1 and 1 = 1")
.setCacheable(true)
.list();
2.创建 Session 方式
sessionFactory.openSession()
sessionFactory.getCurrentSession()
两种创建得到 session 的区别:
openSession 每次得到session 是一个新的。
openSession 每次得到session 事务手动提交,再关闭session
getCurrentSession 获取session 要开启以下配置:
<property name="hibernate.current_session_context_class">thread</property>
getCurrentSession 获取session ,会检查当前线程上有没有session对象,如果有直接从线程上取,没有就调用openSession 创建一个新的 session 对象,并且把该session对象绑定到当前线程中。
getCurrentSession 获取session,由于session 绑定了事务,所以在事务提交后,会自动的关闭session,如果手动再去关闭session 就会报错,但是在hibernate 5.2 以上的版本,就不会存在该问题。
实际开发中使用 getCurrentSession 获取session 对象,只不过将来的session 的上下文不是 线程,就来缓存 SpringSessionContext