在hibernate有三种类型的高速缓存,我们使用最频繁。分别缓存、缓存和查询缓存。下面我们使用这三个缓存中的项目和分析的优点和缺点。

缓存它的作用在于提高性能系统性能,介于应用系统与数据库之间而存在于内存或磁盘上的数据。

我们编程的模式通常是这种page-->filter-->action-->server-->dao-->db,能够在这一个请求过程中的不论什么一点增加缓存,上一篇介绍的是在server层加缓存:service利用aop加缓存

为页面添加缓存:为页面加缓存

首先,来看一下一级缓存它默认开启且非经常常使用。

一级缓存

同是一种缓存经常能够有好几个名字。这是从不同的角度考虑的结果,从缓存的生命周期角度来看一级缓存又能够叫做:sessin缓存、线程级缓存、事务级缓存。

我们编程中线程、事务、session这三个概念是绑定到一起的放到了threadlocal中,同一时候开启同一时候关闭即同生共死也有人叫做request-per-session-transaction编程;

       当session关闭后缓存中的对象会丢失,也就是说两个不同的session中的缓存数据都是不一样的,缓存数据不可以跨session訪问。

缓存数据的数据类型

在一级缓存中缓存的是实体对象。在使用查询方法get() 、load() 、iterate()三个方法查询时都会先查询session缓存。假设有对象则从缓存里面取出来,假设缓存中没有再去数据库里面查询。

    load()測试:測试注意一定要在同一个事务里面,当我在Spring管理的session測试时调用两次load()总是查询两次发出两条SQL语句。还以为session级缓存没有起作用,原来是由于hibernate集成spring之后事务、session都由spring管理。每次调用前后事务一级session都自己主动打开和关闭。自己控制不了中间过程。于是将spring去掉拿到hibernate原session,再手动开发关闭事务这样做能够保证在同一个session、同一个事务里面操作方法,确实是发了一条SQL语句,看以下代码:

    load()、get()方法:

    @Test
public void testLoad()
{
Session session=sf.openSession();
session.beginTransaction(); Category category1=(Category)session.load(Category.class,1);
Category category2=(Category)session.load(Category.class,1);
System.out.println(category1);
System.out.println(category2); session.getTransaction().commit();
session.close();
}

结果

Hibernate: select category0_.id as id0_0_, category0_.name as name0_0_ from Category category0_ where category0_.id=?
hibernate.Category@10efd7c
hibernate.Category@10efd7c

结果不仅发送了一条语句并且两个对象打印出来也是一样的。

load()、get()第一次查询时会发出sql语句,从数据库表里面查询。第二次查询时会先去缓存里面查找。假设没有发生更新改动操作,那么将从缓存中读取数据,否则查询数据库。

save方法

    @Test
public void testGet()
{
Session session=sf.openSession();
session.beginTransaction(); Category category1=new Category();
category1.setName("新闻"); session.save(category1);
Category category2=(Category)session.load(Category.class,category1.getId()); System.out.println(category2.getName());
session.getTransaction().commit();
session.close();
}

save也支持缓存。当运行save方法时首先往session缓存里面加入一条数据,等事务提交或者缓存刷新时才往数据库里面更新,从上面运行过程能够看出仅仅发出了一条插入语句没有发查询语句,由于第二次是从缓存中查询出来的。

PS:save之后运行get或者load须要知道对象的ID,此时save方法运行后尽管数据库里没有数据。可是对象的ID已经生成能够通过这个ID查询对象。

批量插入数据

在批量插入数据的时候採取每次插入一部分数据,例如以下,每次插入20条数据不须要一条一条插入。

	public void testInserBatch() {
Session session = sf.openSession();
session.beginTransaction(); for(int i=0; i<1000; i++) {
Category c = new Category();
c.setName("test" + i);
session.save(c);
if (i%20==0) {
session.flush();
}
} session.getTransaction().commit();
session.close();
}

每次20条数据清理一下缓存,每次清理缓存调用session.flush()方法会发出20条insert语句。可是数据库里面还没有数据等全部数据都发出insert语句统一提交事务。事务同session是一个等级的因此需统一控制事务。

hibernate N+1问题

Hibernate 中常会用到 set 等集合表示 1 对多的关系。在我们做的这个铁科院项目中。在获取实体的时候就能依据关系将关联的对象或者对象集合取出。还能够设定 cacade 进行关联更新和删除。这不得不说 hibernate 的 orm 做得非常好,非常贴近 oo 的使用习惯了。



      可是对数据库訪问还是必须考虑性能问题的。在设定了 1 对多这样的关系之后, 查询就会出现传说中的 n+1 问题。



一对多:在一方。查找得到了 n 个对象,那么又须要将 n 个对象关联的集合取出,于是本来的一条 sql 查询变成了 n+1 条;



多对一:在多方,查询得到了 m 个对象,那么也会将 m 个对象相应的 1 方的对象取出, 也变成了 m+1 ;



      解决这个问题的方法:



1、 使用 fetch 抓取, Hibernate 抓取策略分为单端代理和集合代理的抓取策略。

Hibernate 抓取策略 ( 单端代理的抓取策略) :



保持默认也就是例如以下 :



<many-to-one name="clazz"cascade="save-update" fetch="select" />



fetch="select" 就是另外发送一条 select 语句抓取当前对象关联实体或者集合设置 fetch="join"



<many-to-one name="clazz"cascade="save-update" fetch="join"/>



Hibernate 会通过 select 语句使用外连接来载入器关联实体活集合此时 lazy 会失效



Hibernate 抓取策略 ( 集合代理的抓取策略 ) :



保持默认( fetch="select" )也就是例如以下 :



<set name="students"inverse="true">



<key column="clazz"/>



<one-to-many class="com.june.hibernate.Student"/>



</set>



1)fetch="select" 会另外发出一条语句查询集合



2) 设置fetch="join" 採用外连接集合的 lazy 失效



3) 这仅仅fetch="subselect" 另外发出一条 select 语句抓取前面查询到的全部的实体对象的关联集合 fetch 仅仅对 HQL 查询产生影响其它的则不会

OpenSessionInview问题

这个问题出现是因为load()懒载入导致的,第一次查询数据时使用了懒载入至查询出来数据的ID,当使用数据的时候还须要去数据库里面查询可是此时数据库的session已经关闭,解决此问题两种思路一种是不使用懒载入;其二是在web层开发关闭session,延长session的生命周期。

二级缓存

二级缓存也称为进程级缓存或sessionFactory缓存,也能够叫做集群范围内的缓存,须要第三方来实现。hibernate默认的二级缓存插件为ehcache这个缓存,因为二级缓存是进程级的可能出现多线程并发问题。须要设置缓存的并发策略。

hibernate二级缓存须要第三方插件支持。hibernate默认支持为ehcache关于配置请參考:Spring AOP +EHcache为Service层方法添加缓存

开启二级缓存后对方法的影响

get()/load()

对于这两个方法没啥影响。第一次从数据库里面查询,第二次先推断缓存里面有没有数据假设没有再去数据库里面查询。

查询缓存



查询缓存是针对普通属性结果集的缓存。不缓存实体对象,当和查询缓存关联的表发生改动的时候,查询缓存生命周期结束。里面的数据也随即被清空了。

查询缓存的配置和使用:

List方法读写查询缓存,Iterator不使用查询缓存(查询缓存仅仅对query.list()有效)



      查询缓存的配置。默认不开启hibernate3配置:

	  	<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.use_query_cache">true</property>

代码中,加上一句话

query.setCacheable(true)

一级、二级、查询之间的关系



一级缓存总是开启状态,我们须要关注的是查询缓存和二级缓存。查询缓存能够仅仅开启一个或者两个都打开。

开启二级缓存时,假设两个session先后运行load或者get方法,仅仅运行一条语句第二次会从缓存中查找。先从一级缓存中查询,假设没有再去二级缓存中查找。

一级缓存同二级缓存交互

禁止一级缓存与二级缓存交互,例如以下设置

session.setCacheMode(CacheMode.IGNORE);

打开一个session运行查询,它会先将查询结果保存到一级缓存。待session关闭后。一级缓存中数据清空,因为禁止了一级缓存同二级缓存数据交互,因此,一级缓存关闭后不会将结构保存到二级缓存,打开第二个session后,后再发送一条查询语句,因此二级缓存中没有数据。

查询缓存与二级缓存

开启查询。关闭二级

         假设两次运行query.list()。第一次发送查询语句会将结果对象的id保存到查询缓存中,第二次会先从查询缓存中取出ID。依据id先去一级缓存查找,再二级缓存,假设没有找到会去数据库中查找,一级缓存同session没有关系,仅仅和表有关系。

开启查询,开启二级缓存

两次运行query.list(),第一次发送查询语句将结果

总结:

缓存在一个项目中对于提高系统性能非常重要,除了ehcache之外还有memcache、redis等缓存产品眼下都非经常常使用。redis具有丰富的数据类型以及单线程高效能訪问效率。memcache尽管是多线程但效率还是没有redis高。

这些缓存产品都能够实现分布式缓存,ehcache+rmi能够分布式缓存同步;memcache+redis都支持分布式,redis还提供了高可用性的解决方式:主从复制几个server直接爱你能够切换。

版权声明:本文博客原创文章。博客,未经同意,不得转载。

性能优化(一个)Hibernate 使用缓存(一个、两、查询)提高系统性能的更多相关文章

  1. 我把阿里、腾讯、字节跳动、美团等Android性能优化实战整合成了一个PDF文档

    安卓开发大军浩浩荡荡,经过近十年的发展,Android技术优化日异月新,如今Android 11.0 已经发布,Android系统性能也已经非常流畅,可以在体验上完全媲美iOS. 但是,到了各大厂商手 ...

  2. 【SQL Server性能优化】运用SQL Server的全文检索来提高模糊匹配的效率

    原文:[SQL Server性能优化]运用SQL Server的全文检索来提高模糊匹配的效率 今天去面试,这个公司的业务需要模糊查询数据,之前他们通过mongodb来存储数据,但他们说会有丢数据的问题 ...

  3. 性能优化之Hibernate缓存讲解、应用和调优

    JavaMelody——一款性能监控.调优工具, 通过它让我觉得项目优化是看得见摸得着的,优化有了针对性.而无论是对于分布式,还是非分布,缓存是提示性能的有效工具. 数据层是EJB3.0实现的,而EJ ...

  4. [原]性能优化之Hibernate缓存讲解、应用和调优

    近来坤哥推荐我我们一款性能监控.调优工具--JavaMelody,通过它让我觉得项目优化是看得见摸得着的,优化有了针对性.而无论是对于分布式,还是非分布,缓存是提示性能的有效工具. 数据层是EJB3. ...

  5. oracle性能优化(项目中的一个sql优化的简单记录)

    在项目中,写的sql主要以查询为主,但是数据量一大,就会突出sql性能优化的重要性.其实在数据量2000W以内,可以考虑索引,但超过2000W了,就要考虑分库分表这些了.本文主要记录在实际项目中,一个 ...

  6. web性能优化:详说浏览器缓存

    TOC 背景 浏览器的总流程图 一步一步说缓存 朴素的静态服务器 设置缓存超时时间 html5 Application Cache Last-Modified/If-Modified-Since Et ...

  7. web性能优化之--合理使用http缓存和localStorage做资源缓存

    一.前言 开始先扯点别的: 估计很多前端er的同学应该遇到过:在旧项目中添加新的功能模块.或者修改一些静态文件时候,当代码部署到线上之后,需求方验收OK,此时你送了一口气,当你准备开始得意于自己的ma ...

  8. Hibernate一级缓存(基于查询分析)

    首先我们应该弄清什么是hibernate缓存:hibernate缓存是指为了降低应用程序对物理数据源的访问频次,从而提高应用程序的运行性能的一种策略.我们要将这个跟计算机内存或者cpu的缓存区分开. ...

  9. 利用Injecttion优化编辑的速度,你不是缺一台性能优化的电脑而是缺一个快速编译的工具~

    请前往如下的链接查看优化编译速度: https://www.jianshu.com/p/b2a2f15a3283

  10. 谈谈canvas的性能优化(主要讲缓存问题)

    声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢! canvas玩多了后,就会自动的要开始考虑性能问题了.怎么优化canvas的动画呢? [使用缓存] 使用缓存也就是用离屏canvas进行预 ...

随机推荐

  1. php+sqlite 最佳web服务器

    1 wampserver   支持mysql.每次都启动mysql,可以手动停止.但是运行时有时会很慢. 放弃 2 APS绿色版(Apache+PHP+SQLite)  组件环境:Apache2.2. ...

  2. ng-repeat出现环路输出Duplicates in a repeater are not allowed. Use &#39;track by&#39; expression to specify unique

    采用ng-repeat循环发生错误时,如下面的输出对象: Duplicates in a repeater are not allowed. Use 'track by' expression to ...

  3. OpenCVR 有新成员 OpenCVV OpenCVC

    OpenCVC主要负责OpenCVR报名, OpenCVV支持Android IOS Mac Windows 的client 版权声明:本文博客原创文章,博客,未经同意,不得转载.

  4. Linux 多学习过程

    1Linux流程概述 过程是,一旦运行过程中的程序,他和程序本质上的区别.程序是静态的,他奉命收集指令存储在磁盘上. 进程是动态的概念.他是执行者的程序,包括进程的动态创建.调度和消亡,是Linux的 ...

  5. 它们的定义dialog

    (1)你需要准备自己的自定义对话框样式,是一个布局文件 <?xml version="1.0" encoding="utf-8"? > <Li ...

  6. .net与Java的WebService互调

    本文记录一下.net与Java是如何进行Web Service的互相调用的. 1.准备工作 MyEclipse 10 JDK 1.6.0_13 Visual Studio 2012 .net fram ...

  7. C#枚举数和迭代器

    大道至简,始终认为简洁是一门优秀的编程语言的一个必要条件.相对来说,C#是比较简洁的,也越来越简洁.在C#中,一个关键字或者语法糖在编译器层面为我们做了很多乏味的工作,可能实现的是一个设计模式,甚至是 ...

  8. SQLHlper意识

    经过学习,通过线敲登录的三个例子,敲四行CRUD样品,因此,访问数据库多次,在这些链接库.打开都一样.只是不同的操作将针对不同的表进行.始学习面向对象的思想.当让要对这些不变的要内容要进行打包,提高代 ...

  9. SQL Server中的TempDB管理——TempDB基本知识(为什么需要版本存储区)

    原文:SQL Server中的TempDB管理--TempDB基本知识(为什么需要版本存储区) 参考资料来自: http://blogs.msdn.com/b/sqlserverstorageengi ...

  10. OC本学习笔记Foundatio框架集

        一.OC数组         OC数组是一个类,它也分不可变数组NSArray和可变数组NSMutableArray. 1➣不可变数组的创建 // 创建一个不可变数组.元素为一个OC字符串对象 ...