详解Hibernate缓存与性能优化

缓存概念

缓存 介于应用程序和永久性数据源(文件,数据库等)之间,作用就是降低应用程序直接读取数据源的频率,从而提高应用程序的运行性能。缓存中的数据就是数据源中数据的复制,应用程序在运行时直接读取缓存中的数据。

缓存的物理介质通常是内存,而永久性数据存储源的物理介质通常是硬盘或磁盘,应用程序读写内存的速度显然比读写硬盘的速度快。如果缓存存放的数据非常大,也会用硬盘作为缓存的物理介质。

Hibernate缓存分类

在hibernate中提供了二种缓存机制:一级缓存、二级缓存,因为二级缓存策略是针对于ID查询的缓存策略,对于条件查询则毫无作用,为此,Hibernate提供了针对条件查询的Query Cache(查询缓存)

1、一级缓存。session缓存就是一级缓存。由于session对象的生命周期通常对应一个数据库事物,因此他的缓存范围是事物范围的缓存。一级缓存是必需的,在一级缓存中,持久化类的每个实例都具有唯一的OID;

2、二级缓存。sessionFactory分为内置缓存和外置缓存。

内置缓存是hibernate自带的,不可拆卸,是只读缓存,用来存放映射元数据和预定义SQL语句。

外置缓存是一个可配置的缓存插件,默认sessionFactory不会启用这个缓存插件,外置缓存中的数据就是数据库数据的复制。SessionFactory的外置缓存称为hibernate的二级缓存

二级缓存由sessionFactory负责管理,SessionFactory的生命周期和应用程序的整个进程对应。二级缓存是可选的,可以在每个类或者每个集合的粒度上配置

3、查询缓存 它是Hibernate为查询结果提供的,依赖于二级缓存。

缓存的作用范围

  1. 事物范围 每个事物都有自己的缓存,缓存内数据不会被多个事物并发访问。例如,Hibernate的一级缓存,事物是不能跨多个Session的,Session内数据只能被当前事物访问,因此它属于事物范围内的缓存。
  2. 进程范围 进程内的所有事物共享缓存,进程结束,缓存结束生命周期。例如,Hibernate的二级缓存,SessionFactory对象的生命周期对应应用程序的整个进程,因此它属于进程范围的缓存。
  3. 集群范围 缓存被一个或多个机器上的进程共享。hibernate的二级缓存也可以作为集群范围的缓存。

Hibernate 一级缓存

Session内的缓存即一级缓存。位于缓存中的对象称为持久化对象,它和数据库中的相关记录对应。Session能够在某些时间点(session.flush(); ,tx.commit(); ),按照缓存中对象的变化来执行相关的SQL语句,从而同步更新数据库,这一过程称为刷新缓存。

当应用程序调用 session的 ‘save() ,update() ,saveOrUpdate() ,load() ,get()'等方法,以及调用Query查询接口的' getResultList()'时,如果在'Session'缓存中还不存在相应的对象,Hibernate就会把该对象加入到缓存中,在刷新缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。

综上所述,Session缓存有两大作用:

  1. 减少访问数据库的频率
  2. 保证数据库中的相关记录和缓存中的相应对象同步

session缓存管理方法

  1. evict(); 从session缓存中清除某个对象
  2. clear(); 清空session缓存

ps: flush()强制进行从缓存到数据库的同步

Hibernate 二级缓存

二级缓存是进程或集群范围内的缓存,可以被所有的Session共享,其生命周期和SessionFactory一样。

二级缓存是可配置的插件,Hibernate打包了一些开源缓存实现,提供对他们的内置支持

缓存插件 缓存实现类 查询缓存
EHCache org.hibernate.cache.EhCacheProvider 支持
OSCache org.hibernate.cache.OSCacheProvider 支持
SwarmCache org.hibernate.cache.SwarmCacheProvider 不支持
JBossCache org.hibernate.cache.TreeCacheProvider 支持

为了把上边的缓存插件集成到Hibernate中,Hibernate提供了CacheProvider接口,它是缓存插件与Hibernate之间的适配器。

表格中的实现类是CacheProvider接口的不同实现。

配置二级缓存的步骤如下:

  1. 选择合适的缓存插件,配置其自带的配置文件
  2. 选择需要使用二级缓存的持久化类,设置它的二级缓存的并发访问策略。

以EHCache配置为例,步骤如下

1、将ehcache.xml文件添加到类路径下

在路径'hibernate-release-5.2.6.Final\project\etc\'下复制'ehcache.xml'

标签为每个需要二级缓存的类和集合设定缓存的数据过期策略,配置如下

<cache name="sampleCache1"  -- 缓存的名称,取值为类的完整名称或类的集合名称
 maxElementsInMemory="10000" -- 基于缓存可存放的对象的最大数目
 eternal="false"   -- 如果为true,表示对象永不过期,默认为false
 timeToIdleSeconds="300"  -- 设置允许对象处于空闲状态的最长时间,单位是秒
 timeToLiveSeconds="600"  -- 设置对象允许存在于缓存中最长时间,单位是秒
 overflowToDisk="true"  -- 是否将溢出的对象写到基于硬盘的缓存中
 />

2、开启二级缓存,在hibernate.cfg.xml配置

<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>

3、指定缓存产品提供商

<!-- 指定缓存产品提供商 -->
<property name="hibernate.cache.provider_class">
 <!-- net.sf.ehcache.hibernate.EhCacheProvider -->
 org.hibernate.cache.EhCacheProvider
</property>
<property name="cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</property>

4、指定使用二级缓存的持久化类。修改持久化类的映射文件,为元素添加元素,配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <hibernate-mapping>
 <class name= "com.ytzl.demo.entity.Dept" table ="dept" dynamic-update="true" >
 <cache usage="read-write"/>
 <id name="id" column="d_id" type="java.lang.Integer">
 <generator class="increment"></generator>
 </id>
 <property name="name" column="d_name" type="java.lang.String"></property>
 </class>
 </hibernate-mapping>

cache 的属性

  • usage 是必须的,指定并发访问策略,取值为 transactional(事物缓存),read-write(读/写缓存),nonstrict-read-wirte(非严格读/写缓存),或read-only(只读缓存)。
  • region 可选,默认为类或集合的名字
  • include 可选,取值为non-lazy(当缓存一个对象时,不会缓存它的映射为延迟加载的属性)、all,默认值为all

或者在 hibernate.cfg.xml 的mapping元素后面统一配置 (推荐)

<class-cache usage="read-write" class="com.ytzl.demo.entity.Dept"/>

关闭二级缓存交互

有时候考虑到内存开销问题,需要关闭与二级缓存的交互,可以调用session的' setCacheMode(CacheMode.IGNORE)方法关闭与二级缓存的交互;

CacheMode.IGNORE参数的意思是当前session和二级缓存不再相互作用

二级缓存使用场景

二级缓存并非适合所有场景,使用不当,反而会降低性能。符合如下条件就适合放入二级缓存

  1. 很少修改的数据
  2. 不是很关键的数据,能容忍短时间内督导过期数据
  3. 应用参考的常量数据。它的实例数目有限,实例会被许多其他类的实例引用,实例极少或从来不被修改

二级缓存不适用场景

  1. 经常修改的数据
  2. 财务数据,绝对不允许读到过期数据
  3. 与其他应用共享的数据。如果其他应用修改了数据库中的数据,Hibernate无法自动保证二级缓存的数据与数据库一致

如果不设置“查询缓存”,那么hibernate只会缓存单个持久化对象,如果想缓存使用 findall()list()Iterator()createCriteria()createQuery()等方法获得的数据结果集的话, 就需要在配置文件中设置 hibernate.cache.use_query_cache true 才行

Hibernate查询缓存

上面说到的二级查询,只有在基于id查找对象时才会用到,对于查询则毫无用处。为此,Hibernate提供了针对的查询的查询缓存。

查询缓存依赖于二级缓存,因此使用查询缓存之前要按步骤配置好二级缓存

使用查询缓存的步骤如下

1、在hibernate.cfg.xml中开启查询缓存

<!-- 查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>

2、在程序中启用查询缓存

query.setCacheable(true);

查询缓存的使用场景

  1. 经常使用的查询语句
  2. 对于查询的数据很少有插入、删除或者更新操作

Hibernate性能优化

Hibernate主要从一下几个方面来优化查询性能

  1. 使用迫切左外链接或迫切内链接查询策略、查询缓存等方式,减少select语句的数目,降低访问数据库的频率
  2. 使用延迟加载查询策略等方式避免加载多余的不需要访问的数据
  3. 使用Query接口的iterate()方法减少select语句中的字段,从而降低访问数据库的数据量

HQL优化

HQL优化hibernate程序性能优化的一个方面,HQL的语法和SQL非常类似。HQL是基于SQL的,只是增加了面向对象的封装,如果抛开HQL通Hibernate本身一些缓存机制的关联,HQL的优化技巧通SQL的优化技巧一样,在编写HQL时,需要主要以下几个原则

  1. 避免 or操作的使用不当。如果where子句中有多个条件,并且其中某个条件没有索引,使用or,将导致全表扫描。
  2. 避免使用 not 。如果where子句的条件包含not关键字,那么执行时该字段的索引失效。这些需要分成不同情况区别对待,对于 不大于(不多于)、不小于(不少于)建议使用运算符来替代not
  3. 避免like的特殊形式。某些情况下,会在where子句条件中使用用like。如果like以一个“%”或“_”开始即前模糊,则该字段的索引不起作用。目前没有什么解决 办法。
  4. 避免 having子句。在分组查询中,可在两个位置指定条件,一是where子句中,二是having子句中。尽可能的在where子句而不是在having子句中指定条件。having是在检索出所有记录后对结果集进行过滤。这个处理需要一定的开销,而where子句限制记录数目,能减少这方面的开销
  5. 避免使用 distinct 。指定distinct会导致在结果中删除重复的行,这会对处理时间造成一定的影响。
  6. 索引在以下情况失效,应注意使用

只要对字段使用函数,该字段的索引将不起作用。

只要对该字段进行计算,该字段的索引将不起作用。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • java模拟hibernate一级缓存示例分享

    纯Java代码模拟Hibernate一级缓存原理,简单易懂. 复制代码 代码如下: import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map; public class LevelOneCache { //这个对象就是用来模拟hibernate一级缓存的 private static Map<Integer, Student> stus=new HashMap&l

  • Hibernate框架中的缓存技术详解

    本文实例讲述了Hibernate框架中的缓存技术.分享给大家供大家参考,具体如下: Hibernate框架的缓存分为Session的缓存.SessionFactory的缓存,也称为一级缓存和二级缓存. 一级缓存: 一级缓存是Session级的缓存,其生命周期很短,与Session相互对应,由Hibernate进行管理,属于事务范围的缓存.当程序调用 Session的load()方法.get()方法.save()方法.saveOrUpdate()方法.update()方法或查询接口方法时,Hibe

  • 浅析Java的Hibernate框架中的缓存和延迟加载机制

    hibernate一级缓存和二级缓存的区别 缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据. 缓存的介质一般是内存,所以读写速度很快.但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质.缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期. Hibernate的缓存包括Sessi

  • 详解Java的Hibernate框架中的缓存与原生SQL语句的使用

    Hibernate缓存 缓存是所有关于应用程序的性能优化和它位于应用程序和数据库之间,以避免数据库访问多次,让性能关键型应用程序有更好的表现. 缓存对Hibernate很重要,它采用了多级缓存方案下文所述: 第一级缓存: 第一级缓存是Session的缓存,是一个强制性的缓存,通过它所有的请求都必须通过. Session对象不断自身的动力的对象,提交到数据库之前. 如果发出多个更新一个对象,Hibernate试图拖延尽可能长的时间做了更新,以减少发出的更新SQL语句的数量.如果您关闭会话,所有被缓

  • Spring 整合 Hibernate 时启用二级缓存实例详解

    Spring 整合 Hibernate 时启用二级缓存实例详解 写在前面: 1. 本例使用 Hibernate3 + Spring3: 2. 本例的查询使用了 HibernateTemplate: 1. 导入 ehcache-x.x.x.jar 包: 2. 在 applicationContext.xml 文件中找到 sessionFactory 相应的配置信息并在设置 hibernateProperties 中添加如下代码: <!-- 配置使用查询缓存 --> <prop key=&q

  • 详解Java的Hibernate框架中的缓存与二级缓存

    缓存 今天我们就来讲一下hibernate中实体状态和hibernate缓存.  1)首先我们先来看一下实体状态:  实体状态主要分三种:transient,persitent,detached.  看英文应该就大概明白了吧.  transient:是指数据还没跟数据库中的数据相对应.  persistent:是指数据跟数据库中的数据相对应,它的任何改变都会反映到数据库中.  detached:是指数据跟数据库中的数据相对应,但由于session被关闭,它所做的修改不会对数据库的记录造成影响.

  • Hibernate缓存详解

    1. 什么是缓存? 数据库的缓存指的是应用程序和物理数据源之间的数据.即把物理数据源的数据复制到缓存.有了缓存,可以降低应用程序对物理数据源的访问频率,从而提高效率.缓存的介质一般是内存,也可以是硬盘. Hibernate的缓存有三种类型:一级缓存.二级缓存和查询缓存. 2. 一级缓存 一级缓存即Session缓存,由Session自动进行管理,不需要程序进行干预.一级缓存根据对象的ID进行加载和缓存.如下面的代码: @Override public void testCache() { //

  • SSH框架网上商城项目第16战之Hibernate二级缓存处理首页热门显示

    网上商城首页都有热门商品,那么这些商品的点击率是很高的,当用户点击某个热门商品后需要进入商品的详细信息页面,就像淘宝里面那样.那么每次点击都要去后台查询一下该商品的详细信息,就会发送相应的sql语句,每次刷新一下详细页面也会发sql语句,这样的话,性能肯定会受到很大的影响.那么使用Hibernate的二级缓存就可以解决这个问题. 有些人可能会想,我们可以使用重定向,这样的话,在用户第一次访问的时候把信息查出来放到session中,以后每次用户刷新就可以去session中拿了,这样就不用去数据库中

  • 详解Java的Hibernate框架中的注解与缓存

    注解 Hibernate注解是一个没有使用XML文件来定义映射的最新方法.可以在除或替换的XML映射元数据使用注解. Hibernate的注解是强大的方式来提供元数据对象和关系表的映射.所有的元数据被杵到一起的代码POJO java文件这可以帮助用户在开发过程中同时要了解表的结构和POJO. 如果打算让应用程序移植到其他EJB3规范的ORM应用程序,必须使用注解来表示映射信息,但仍然如果想要更大的灵活性,那么应该使用基于XML的映射去. 环境设置Hibernate注释 首先,必须确保使用的是JD

  • 详解Hibernate缓存与性能优化

    缓存概念 缓存 介于应用程序和永久性数据源(文件,数据库等)之间,作用就是降低应用程序直接读取数据源的频率,从而提高应用程序的运行性能.缓存中的数据就是数据源中数据的复制,应用程序在运行时直接读取缓存中的数据. 缓存的物理介质通常是内存,而永久性数据存储源的物理介质通常是硬盘或磁盘,应用程序读写内存的速度显然比读写硬盘的速度快.如果缓存存放的数据非常大,也会用硬盘作为缓存的物理介质. Hibernate缓存分类 在hibernate中提供了二种缓存机制:一级缓存.二级缓存,因为二级缓存策略是针对

  • 详解GaussDB for MySQL性能优化

    背景 我们先来看看MySQL 8.0的事务提交的大致流程 以上流程,是MySQL8.0对WAL原则的一种实现,这个流程意味着,任何一个事务的提交,一定要完成write buffer和flush to disk流程. 然而那么这个流程中,有一个问题:每个服务器的CPU是有限的,服务器能处理的Thread也是有上限的,那么当我们的业务的并发数量,远远大于我们服务器能并行处理的数量时,那么后来的事务,只能等待前面的事务提交后才能被处理.在这之前,他们什么也做不了.因此,在大并发场景下,如何进一步提升线

  • 详解Hibernate注解方式的二级缓存

    详解Hibernate注解方式的二级缓存 hibernate默认情况下是支持一级缓存,也就是session级的缓存的,而默认情况下是不支持二级缓存,即sessionFactory级的缓存的,二级缓存        一般比较少去考虑它,除非对效率要求非常高的时候, 这时侯如果我们的某一个实体要在多个session里面使用需要用到session间的缓存的时候就可以进行配置来实现二级缓存了! 在看文档的时候说可以在persistence.xml里面进行配置,但我一般是不用这个文件的,就直接使用注解!

  • Android Bitmap详解及Bitmap的内存优化

    Android Bitmap详解及Bitmap的内存优化 一.Bitmap: Bitmap是Android系统中的图像处理的最重要类之一.用它可以获取图像文件信息,进行图像剪切.旋转.缩放等操作,并可以指定格式保存图像文件. 常用方法: public void recycle() // 回收位图占用的内存空间,把位图标记为Dead public final boolean isRecycled() //判断位图内存是否已释放 public final int getWidth() //获取位图的

  • 详解高性能缓存Caffeine原理及实战

    目录 一.简介 二.Caffeine 原理 2.1.淘汰算法 2.1.1.常见算法 2.1.2.W-TinyLFU 算法 2.2.高性能读写 2.2.1.读缓冲 2.2.2.写缓冲 三.Caffeine 实战 3.1.配置参数 3.2.项目实战 四.总结 一.简介 下面是Caffeine 官方测试报告. 由上面三幅图可见:不管在并发读.并发写还是并发读写的场景下,Caffeine 的性能都大幅领先于其他本地开源缓存组件. 本文先介绍 Caffeine 实现原理,再讲解如何在项目中使用 Caffe

  • 详解Jackson 使用以及性能介绍

    直接上代码,看下最简单也是最常用的方法,将Object 转为 JSON 以及将Json转为Object方式 public class TestJackson { public static void main(String[] args) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); Map<String,Object> params = new HashMap<>(); params.pu

  • 详解redis缓存与数据库一致性问题解决

    数据库与缓存读写模式策略 写完数据库后是否需要马上更新缓存还是直接删除缓存? (1).如果写数据库的值与更新到缓存值是一样的,不需要经过任何的计算,可以马上更新缓存,但是如果对于那种写数据频繁而读数据少的场景并不合适这种解决方案,因为也许还没有查询就被删除或修改了,这样会浪费时间和资源 (2).如果写数据库的值与更新缓存的值不一致,写入缓存中的数据需要经过几个表的关联计算后得到的结果插入缓存中,那就没有必要马上更新缓存,只有删除缓存即可,等到查询的时候在去把计算后得到的结果插入到缓存中即可. 所

  • 详解Vue开发网站seo优化方法

    因为用了vue等js的数据绑定机制来展示页面数据,爬虫获取到的html是模型页面而不是最终数据的渲染页面,搜索引擎是不回去执行请求到的js.vue的项目都是ajax请求数据,引擎爬虫进入页面获取不到文字内容,现在大多数解决方案是不采用ajax渲染数据,而是采用server端渲染,也就是所谓的SSR. 目前基于vue的方案是Nuxt.js,同类型的也有React版的Nuxt.js所以服务端渲染就是尽量在服务器发送到浏览器前,页面上是有数据可让爬虫进行爬取 方法一.利用prerender-spa-p

  • 详解Hibernate cascade级联属性的CascadeType的用法

    详解Hibernate cascade级联属性的CascadeType的用法 cascade(级联) 级联在编写触发器时经常用到,触发器的作用是当 主控表信息改变时,用来保证其关联表中数据同步更新.若对触发器来修改或删除关联表相记录,必须要删除对应的关联表信息,否则,会存有脏数据.所以,适当的做法是,删除主表的同时,关联表的信息也要同时删除,在hibernate中,只需设置cascade属性值即可. cascade表示级联操作,在hibernate配置注解@OneToOne,@OneToMany

  • 详解hibernate自动创建表的配置

    详解hibernate自动创建表的配置 配置自动创建表: <prop key="hibernate.hbm2ddl.auto">update</prop>//首次创建项目时用,项目稳定后一般注释这里有4个值: update:表示自动根据model对象来更新表结构,启动hibernate时会自动检查数据库,如果缺少表,则自动建表:如果表里缺少列,则自动添加列. 还有其他的参数: create:启动hibernate时,自动删除原来的表,新建所有的表,所以每次启动后

随机推荐