1.Hibernate的cache介绍:

  Hibernate实现了良好的Cache机制,可以借助Hibernate内部的Cache迅速提高系统的数据读取性能。Hibernate中的Cache可分为两层:一级Cache和二级Cache。

  第一级别的缓存是Session级别的缓存,是属于事务范围的缓存,由Hibernate管理,一般无需进行干预。

  二级缓存是属于SessionFactory级别的缓存机制。第二级别的缓存是SessionFactory级别的缓存,是属于进程范围的缓存。跨多个session的缓存,mybatis的二级缓存是跨多个SqlSession的缓存。

一级缓存:

  Hibernate默认是开启一级缓存的,一级缓存存放在session上,属于事务级数据缓冲。

  对象分为三种状态:瞬时状态、持久化状态、游离状态.其实我们调用session.save或者session.update或者session.saveOrUpdate只是为了将对象的状态改变为持久态(将对象存入session一级缓存)。一级缓存

中的对象就是和session关联,session中有一级缓存区和快照区,执行事务提交的时候会判断快照中对象和缓存中对应的对象是否一致,如果一致不会执行修改SQL、不一致会执行修改SQL。

二级缓存

  在SessionFactory,所有的Session共享同一个二级Cache。二级Cache的内部如何实现并不重要,重要的是采用哪种正确的缓存策略,以及采用哪个Cache提供器。

  

2.二级缓存分类:

二级缓存也分为了两种

  内置缓存:Hibernate自带的,不可卸载,通常在Hibernate的初始化阶段,Hibernate会把映射元数据和预定义的SQL语句放置到SessionFactory的缓存中。该内置缓存是只读的。

  外置缓存:通常说的二级缓存也就是外置缓存,在默认情况下SessionFactory不会启用这个缓存插件,外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存或者硬盘

3.并发访问策略

  我们一般用的缓存策略是read-only或者是read-write。

transactional

(事务型)

仅在受管理的环境中适用

提供Repeatable Read事务隔离级别

适用经常被读,很少修改的数据

可以防止脏读和不可重复读的并发问题

缓存支持事务,发生异常的时候,缓存也能够回滚

read-write

(读写型)

提供Read Committed事务隔离级别

在非集群的环境中适用

适用经常被读,很少修改的数据

可以防止脏读

更新缓存的时候会锁定缓存中的数据

nonstrict-read-write

(非严格读写型)

适用极少被修改,偶尔允许脏读的数据(两个事务同时修改数据的情况很少见)

不保证缓存和数据库中数据的一致性

为缓存数据设置很短的过期时间,从而尽量避免脏读

不锁定缓存中的数据

read-only

(只读型)

适用从来不会被修改的数据(如参考数据)

在此模式下,如果对数据进行更新操作,会有异常

事务隔离级别低,并发性能高

在集群环境中也能完美运作

适合放入缓存的数据:

  很少被修改
  不是很重要的数据,允许出现偶尔的并发问题
不适合放入二级缓存中的数据:
  经常被修改
  财务数据,绝对不允许出现并发问题
  与其他应用数据共享的数据

4.在Hibernate中使用EhCache:

1.导包:

hibernate5需要引入slf4j的包,否则会报错。。。。。。。。。。。。。。。。。

2.hibernate.cfg.xml中开启二级缓存:(在hbm文件中配置)

<?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> <!--
#hibernate.dialect org.hibernate.dialect.MySQLDialect
#hibernate.dialect org.hibernate.dialect.OracleDialect
#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
#hibernate.connection.driver_class com.mysql.jdbc.Driver
#hibernate.connection.url jdbc:mysql:///test
#hibernate.connection.username gavin
#hibernate.connection.password
-->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password">123456</property> <!-- <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
<property name="hibernate.connection.username">sbgl</property>
<property name="hibernate.connection.password">sbgl</property> -->
<!-- 数据库方言
不同的数据库中,sql语法略有区别. 指定方言可以让hibernate框架在生成sql语句时.针对数据库的方言生成.
sql99标准: DDL 定义语言 库表的增删改查
DCL 控制语言 事务 权限
DML 操纵语言 增删改查
注意: MYSQL在选择方言时,请选择最短的方言.
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 使用二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!--设置缓存的类型,设置缓存的提供商 -->
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property> <!-- #hibernate.show_sql true
#hibernate.format_sql true
-->
<!-- 将hibernate生成的sql语句打印到控制台 -->
<property name="hibernate.show_sql">true</property>
<!-- 将hibernate生成的sql语句格式化(语法缩进) -->
<property name="hibernate.format_sql">true</property>
<!--
## auto schema export 自动导出表结构. 自动建表
#hibernate.hbm2ddl.auto create 自动建表.每次框架运行都会创建新的表.以前表将会被覆盖,表数据会丢失.(开发环境中测试使用)
#hibernate.hbm2ddl.auto create-drop 自动建表.每次框架运行结束都会将所有表删除.(开发环境中测试使用)
#hibernate.hbm2ddl.auto update(推荐使用) 自动生成表.如果已经存在不会再生成.如果表有变动.自动更新表(不会删除任何数据).
#hibernate.hbm2ddl.auto validate 校验.不自动生成表.每次启动会校验数据库中表是否正确.校验失败.
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 引入orm元数据
路径书写: 填写src下的路径
-->
<mapping resource="cn/qlq/domain/Customer.hbm.xml" />
<mapping resource="cn/qlq/domain/LinkMan.hbm.xml" />
<mapping resource="cn/qlq/domain/User.hbm.xml" />
<mapping resource="cn/qlq/domain/Role.hbm.xml" />
<mapping resource="cn/qlq/domain/TestType.hbm.xml" /> </session-factory>
</hibernate-configuration>

上面开启是hibernate5开启二级缓存,下面是hibernate4开启二级缓存:

    <!--但是在 hibernate 4中设置缓存提供商时是这样设置的 -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_query_cache">true</property>

3.导入encache.xml(放在classpath目录下)

<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>

4.Customer.hbm.xml中开启二级缓存配置(亲测有效)

为了保险起见 我们需要给相对应的model  实现一个序列化接口 implements Serializable

或者在cfg中:(自己测试的时候报错)

        <!-- 缓存对象 -->
   <class-cache usage="read-write" class="cn.qlq.domain.Customer"/>
<!-- 缓存集合 -->
<collection-cache usage="read-only" collection="cn.qlq.domain.Customer.linkMens"/>

  上面配置方式二选一,我选择在hbm文件中开启二级缓存。

5.测试二级查询缓存

HibernateUtil,java工具类(开启session与开启与线程绑定的session)

package cn.qlq.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry; public class HibernateUtil { private static SessionFactory sessionFactory; // 创建一个对象,一个web项目只有一个SessionFactory
static {
// 3.3以及之前的版本构建会话工厂对象
// SessionFactory sessionFactory = new
// Configuration().configure().buildSessionFactory(); // 5.0之后获取SessionFactory
// 创建服务注册对象
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
// 创建会话工厂对象
sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
} // 获得session => 获得全新session
public static Session openSession() {
return sessionFactory.openSession();
} // 获得session => 获得与线程绑定的session
public static Session getCurrentSession() {
return sessionFactory.getCurrentSession();
} /**
* 测试方法
*
* @param args
*/
public static void main(String[] args) {
System.out.println(HibernateUtil.openSession());
} }

测试二级缓存:

package cn.qlq.secondaryCache;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test; import cn.qlq.domain.Customer;
import cn.qlq.util.HibernateUtil; /**
* 测试二级缓存
*
* @author liqiang
*
*/
public class SecondaryCache {
@Test
public void test1() {
// 1.打开两个session(不是与线程绑定的session)
Session session1 = HibernateUtil.openSession();
Transaction tx1 = session1.beginTransaction();
Customer customer = session1.get(Customer.class, 15l);
System.out.println(customer);
tx1.commit();
session1.close();
System.out.println("--------华丽的分割线----------"); Session session2 = HibernateUtil.openSession();
Transaction tx2 = session2.beginTransaction();
Customer customer2 = session2.get(Customer.class, 15l);
System.out.println(customer2);
tx2.commit();
session2.close();
}
}

结果: 

  只在第一次查询的时候发出SQL请求,第二次获取的时候不会发出SQL请求。证明二级缓存生效。

Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_linkman as cust_lin6_0_0_,
customer0_.cust_phone as cust_pho7_0_0_,
customer0_.cust_mobile as cust_mob8_0_0_
from
cst_customer customer0_
where
customer0_.cust_id=?
Customer [cust_id=15, cust_name=ttt]
--------华丽的分割线----------
Customer [cust_id=15, cust_name=ttt]

6.测试缓存策略:

  继续使用上面的缓存策略(read-only),我们进行修改操作:

package cn.qlq.secondaryCache;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test; import cn.qlq.domain.Customer;
import cn.qlq.util.HibernateUtil; /**
* 测试二级缓存
*
* @author liqiang
*
*/
public class SecondaryCache {
@Test
public void test1() {
// 1.打开两个session(不是与线程绑定的session)
Session session1 = HibernateUtil.openSession();
Transaction tx1 = session1.beginTransaction();
Customer customer = session1.get(Customer.class, 15l);
customer.setCust_name("xxxxx");
tx1.commit();
session1.close();
System.out.println("--------华丽的分割线----------");
}
}

报错:

修改缓存策略为read-write,代码还是上面的修改的代码继续进行访问:

结果正常打印日志且修改数据库:

Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_linkman as cust_lin6_0_0_,
customer0_.cust_phone as cust_pho7_0_0_,
customer0_.cust_mobile as cust_mob8_0_0_
from
cst_customer customer0_
where
customer0_.cust_id=?
Hibernate:
update
cst_customer
set
cust_name=?,
cust_source=?,
cust_industry=?,
cust_level=?,
cust_linkman=?,
cust_phone=?,
cust_mobile=?
where
cust_id=?
--------华丽的分割线----------

接下来还会演技hibernate整合redis进行二级缓存,与mybatis一样进行整合redis进行二级缓存。。。。。。。。。。。。。。。。。(未完待续) 

参考:https://blog.csdn.net/luckyzhoustar/article/details/47748179

Hibernate二级缓存(未完待续)的更多相关文章

  1. 关于DOM的一些总结(未完待续......)

    DOM 实例1:购物车实例(数量,小计和总计的变化) 这里主要是如何获取页面元素的节点: document.getElementById("...") cocument.query ...

  2. odoo11 model+Recordset 基础未完待续

    Model 一个模型代表了一个业务对象 本质上是一个类,包含了同django flask一样的数据字段 所有定义在模型中的方法都可以被模型本身的直接调用 现在编程范式有所改变,不应该直接访问模型,而是 ...

  3. Go web编程学习笔记——未完待续

    1. 1).GOPATH设置 先设置自己的GOPATH,可以在本机中运行$PATH进行查看: userdeMacBook-Pro:~ user$ $GOPATH -bash: /Users/user/ ...

  4. CC2530学习路线-基础实验-串口通讯发送字符串(4 未完待续)

    目录 1. 前期预备知识 1.1 串口通讯电路图 1.2 实验相关寄存器 1.2 常用波特率设置 本章未完待续..... 原来写的文章已经丢失了,只能找到这一小部分,看什么时候有时间再补上. 1. 前 ...

  5. git安装与使用,未完待续... ...

    ​ 目录 一.git概念 二.git简史 三.git的安装 四.git结构 五.代码托管中心-本地库和远程库的交互方式 六.初始化本地仓库 七.git常用命令 1.add和commit命令 2.sta ...

  6. javascript有用小功能总结(未完待续)

    1)javascript让页面标题滚动效果 代码如下: <title>您好,欢迎访问我的博客</title> <script type="text/javasc ...

  7. ASP.NET MVC 系列随笔汇总[未完待续……]

    ASP.NET MVC 系列随笔汇总[未完待续……] 为了方便大家浏览所以整理一下,有的系列篇幅中不是很全面以后会慢慢的补全的. 学前篇之: ASP.NET MVC学前篇之扩展方法.链式编程 ASP. ...

  8. 我的SQL总结---未完待续

    我的SQL总结---未完待续 版权声明:本文为博主原创文章,未经博主允许不得转载. 总结: 主要的SQL 语句: 数据操作(select, insert, delete, update) 访问控制(g ...

  9. virtualbox搭建ubuntu server nginx+mysql+tomcat web服务器1 (未完待续)

    virtualbox搭建ubuntu server nginx+mysql+tomcat web服务器1 (未完待续) 第一次接触到 linux,不知道linux的确很强大,然后用virtualbox ...

随机推荐

  1. scrapy 爬虫怎么写入日志和保存信息

    写入日志: 首先我的爬虫 name= article scrapy crawl article -s LOG_FILE=wiki.log 输出为不同格式: scrapy crawl article - ...

  2. FPGA---Basys3(实验内容汇总贴)

    前言 本博文为FPGA---Basys3入门板的实验汇总帖子. 实验指导书 实验源码github地址 实验目录 组合逻辑电路设计 编码器 比较器 全加器 时序逻辑电路设计 D 触发器的实现 同步复位的 ...

  3. Oracle 最新版本变化 转帖

    版本更迭 http://www.sohu.com/a/163264045_505827 Oracle Database的下一个版本将是 Oracle 18. 目的 为了更快的.通过每年的版本发布将新特 ...

  4. (转)linux 内存管理——内核的shmall 和shmmax 参数

    内核的 shmall 和 shmmax 参数 SHMMAX= 配置了最大的内存segment的大小 ------>这个设置的比SGA_MAX_SIZE大比较好. SHMMIN= 最小的内存seg ...

  5. 【华为机试】—— 15.求int型正整数在内存中存储时1的个数

    题目 解法 import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner ...

  6. NESTED最终与外部事务合并在一起提交

    NESTED最终与外部事务合并在一起提交

  7. MT【86】两个绝对值之和最大

    分析:这里只需要注意到$(|x|+|y|)_{max}=max\{|x+y|,|x-y|\}$,所以只需求$max\{|20a|,|14b|\}$ 进而变成熟悉的反解系数问题.容易知道最大值为$a=2 ...

  8. 基于Docker持续交付平台建设的实践

    导读:中国五矿和阿里巴巴联手打造的钢铁服务专业平台五阿哥,通过集结阿里巴巴在大数据.电商平台和互联网产品技术上的优势,为终端用户带来一站式采购体验.本文是五阿哥运维技术团队针对Docker容器技术在如 ...

  9. CentOS安装git及使用Gitolite来管理版本库

    首先吐槽一下网上的各种教程,大部分都扯蛋,估计都是些所谓的"编辑"在网上瞎抄来的-- 以下内容都是基于CentOS的服务器端,Mac OS X的客户端. 如果是使用的Windows ...

  10. bzoj1008/luogu3197 越狱 (快速幂)

    算$m^n-m*(m-1)^{n-1}$,就是总的减去不越狱的,不越狱就每次都选一个和上一个不一样的