博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Hibernate二级缓存(未完待续)
阅读量:5884 次
发布时间:2019-06-19

本文共 7035 字,大约阅读时间需要 23 分钟。

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文件中配置)

com.mysql.jdbc.Driver
jdbc:mysql:///hibernate
sa
123456
org.hibernate.dialect.MySQLDialect
true
org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
true
true
update

 

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

org.hibernate.cache.EhCacheProvider
true

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

 

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

 

 

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

 

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

  

 

  上面配置方式二选一,我选择在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进行二级缓存。。。。。。。。。。。。。。。。。(未完待续) 

 

参考:

转载地址:http://xblix.baihongyu.com/

你可能感兴趣的文章
Js获取当前页面URL各种参数
查看>>
删除链表的倒数第N个节点
查看>>
DrQA基于维基百科数据的开放域问答机器人实战教程
查看>>
阿里云发布ET工业大脑开放平台,全球首个工业智能的孵化基地
查看>>
Cannot load JDBC driver class 'oracle.jdbc.OracleDriver'
查看>>
Python3 & OpenCV之环境搭建(win10)
查看>>
优雅地使用 mybatis-generator
查看>>
使用Supervisor 管理.net core mvc部署
查看>>
java多线程之延迟初始化
查看>>
webpack配置React开发环境(上)
查看>>
Dubbo 3.0 预览版解读,支持 Filter 链的异步化
查看>>
第190天:js---String常用属性和方法(最全)
查看>>
go-mir v1.0.0 发布 用 Go 结构体标签定义 handler 路由信息的辅助库
查看>>
今年全球游戏市场13%的收入将属于腾讯
查看>>
Git 远程推送被拒绝的一种解决方案
查看>>
《战争论》核心原则
查看>>
阿里云云数据库RDS秒级监控功能解锁,通宵加班找故障将成为过去式
查看>>
Ubuntu常用软件安装(附截图软件、FTP、卸载命令)
查看>>
以太坊MetaMask钱包插件使用教程
查看>>
技术大牛论道HBase 3.0 可能的新特性
查看>>