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. TensorFlow常用API汇总

    1.tensorflow的基本运作为了快速的熟悉TensorFlow编程,下面从一段简单的代码开始: import tensorflow as tf #定义‘符号’变量,也称为占位符 a = tf.p ...

  2. DEP

    DEP(Data execution protect)数据执行保护,这个功能需要操作系统和硬件的共同支持才可以生效.DEP的原理就是在系统的内存页中设置了一个标志位,标示这个内存页的属性(可执行). ...

  3. 解决局域网IP冲突

    进入cmd ipconfig -all 查看现有IP,发现IP不是192.168.1.*的形式,而是192.168.0.*等异常 ipconfig -release  释放现有IP ipconfig ...

  4. CentOS下面磁盘扩容处理

    1. 给虚拟机增加一块硬盘: 过程不表 2. 增加了硬盘之后需要重启一下 查看磁盘 ls /dev/sd* 3. 使用  gdisk 处理磁盘 注意 这里面fdisk 貌似没法处理成 LVM 必须使用 ...

  5. 【loj6029】「雅礼集训 2017 Day1」市场 线段树+均摊分析

    题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有四种:区间加.区间下取整除.区间求最小值.区间求和. $n\le 100000$ ,每次加的数在 $[-10^4,10^4]$ 之 ...

  6. 【大数据】Spark性能优化和故障处理

    第一章 Spark 性能调优 1.1 常规性能调优 1.1.1 常规性能调优一:最优资源配置 Spark性能调优的第一步,就是为任务分配更多的资源,在一定范围内,增加资源的分配与性能的提升是成正比的, ...

  7. python--inspect模块

    inspect模块主要提供了四种用处: 1.对是否是模块.框架.函数进行类型检查 2.获取源码 3.获取类或者函数的参数信息 4.解析堆栈 一.type and members 1. inspect. ...

  8. Number Clicker CodeForces - 995E(双向bfs)

    双向bfs  注意数很大  用map来存 然后各种难受....

  9. 特殊符号 UNICODE编码

    特殊符号 UNICODE编码 =================== Start ⇠  箭头类 符号 UNICODE 符号 UNICODE HTML JS CSS HTML JS CSS ⇠ & ...

  10. oracle 查看临时表空间temp 的使用情况以及扩展表空间

    SELECT D.TABLESPACE_NAME,SPACE "SUM_SPACE(M)",BLOCKS SUM_BLOCKS, USED_SPACE )/SPACE*,) &qu ...