JavaMelody——一款性能监控、调优工具,

通过它让我觉得项目优化是看得见摸得着的,优化有了针对性。而无论是对于分布式,还是非分布,缓存是提示性能的有效工具。

数据层是EJB3.0实现的,而EJB3.0内部也是通过Hibernate实现的,而Hibernate本身提供了很好的缓存机制,我们只需要学会使用它驾驭它就够了。

缓存的机能可以简单理解为将从数据库中访问的数据放在内存中,在以后再次使用到这些数据时可以直接从内存中读取而不必要再次访问数据库,尽量减少和数据库的交互提高性能。

概念讲解

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

一、一级缓存:

一级缓存是hibernate自带的,不受用户干预,其生命周期和session的生命周期一致,当前session一旦关闭,一级缓存就会消失,因此,一级缓存也叫session缓存或者事务级缓存,一级缓存只存储实体对象,不会缓存一般的对象属性,即:当获得对象后,就将该对象缓存起来,如果在同一个session中再去获取这个对象时,它会先判断缓存中有没有这个对象的ID,如果有,就直接从缓存中取出,否则,则去访问数据库,取了以后同时会将这个对象缓存起来。

二、二级缓存:

二级缓存也称为进程缓存或者sessionFactory级的缓存,它可以被所有的session共享,二级缓存的生命周期和sessionFactory的生命周期一致,二级缓存也是只存储实体对象

二级缓存的一般过程如下:

①:条件查询的时候,获取查询到的实体对象

②:把获得到的所有数据对象根据ID放到二级缓存中

③:当Hibernate根据ID访问数据对象时,首先从sesison的一级缓存中查,查不到的时候如果配置了二级缓存,会从二级缓存中查找,如果还查不到,再查询数据库,把结果按照ID放入到缓存中

④:进行delete、update、add操作时会同时更新缓存

三、查询缓存:

查询缓存是对普通属性结果集的缓存,对实体对象的结果集只缓存id,对于经常使用的查询语句,如果启用了查询缓存,当第一次执行查询语句时,Hibernate会把查询结果存放在二级缓存中,以后再次执行该查询语句时,只需从缓存中获得查询结果,从而提高查询性能,查询缓存中以键值对的方式存储的,key键为查询的条件语句(具体的key规则应该是:类名+方法名+参数列表),value为查询之后等到的结果集的ID列表

查询缓存的一般过程如下:

①:Query Cache保存了之前查询执行过的SelectSQL,以及结果集等信息组成一个Query Key

②:当再次遇到查询请求的时候,就会根据QueryKey从QueryCache中找,找到就返回,但当数据表发生数据变动的话,hbiernate就会自动清除QueryCache中对应的Query Key

我们从查询缓存的策略中可以看出,Query Cache只有在特定的条件下才会发挥作用,而且要求相当严格:

①:完全相同的SelectSQL重复执行

②:重复执行期间,QueryKey对应的数据表不能有数据变动

启用缓存的配置

EJB中配置查询缓存和二级缓存

1、在persistence.xml中启用缓存

<persistence-unitname="gxpt-qx-entity" transaction-type="JTA" >
<!--对jpa进行性能测试 -->
<provider>net.bull.javamelody.JpaPersistence</provider> <jta-data-source>java:/MySqlDS</jta-data-source>
<!--<jta-data-source>java:/MyOracleDS</jta-data-source> --> <properties>
<!-- <propertyname="hibernate.dialect"value="org.hibernate.dialect.Oracle10gDialect"/> -->
<propertyname="hibernate.dialect"value="org.hibernate.dialect.MySQLDialect"/>
<propertyname="hibernate.hbm2ddl.auto" value="update" />
<propertyname="hibernate.show_sql" value="true" /> <!--指定二级缓存产品的提供商 -->
<propertyname="hibernate.cache.provider_class"
value="net.sf.ehcache.hibernate.SingletonEhCacheProvider"/>
<!-- <propertyname="hibernate.cache.region.factory_class"
value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>-->
<!--开启二级缓存 -->
<propertyname="hibernate.cache.use_second_level_cache"value="true"/>
<!--开启查询缓存 -->
<propertyname="hibernate.cache.use_query_cache"value="true"/>
<!--指定缓存配置文件位置 -->
<propertyname="hibernate.cache.provider_configuration_file_resource_path"
value="/ehcache.xml"/> </properties>
</persistence-unit>

2、通过注解指定User类使用二级缓存

@Entity
@Table(name="tq_user")
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
publicclass User

3、开启查询缓存,除了在persistence.xml中有以上配置外,还需要在底层代码手动开启查询缓存

query.setHint("org.hibernate.cacheable", true);

或者query.setCacheable(true);

性能测试

通过sql语句

1、二级缓存关闭时,查询缓存开启和关闭情况对比*****普通属性查询

public String myCache() {
List<String> strings = this.userServiceImpl
.search("selectu.username from User u where id<4 order by id asc");
for (String str : strings){
System.out.println("username:" + str);
} System.out.println("===================================");
List<String> strings2 =this.userServiceImpl
.search("select u.usernamefrom User u where id<4 order by id asc");
for (String str : strings2){
System.out.println("username:" + str);
}
return "/mycache";

当前二级缓存为关闭状态,看看查询缓存关闭时的查询结果:

  public List<String> search(Stringhql) {
List<String> rtnStrs = newArrayList<String>();
try {
Session session = this.sessionFactory.openSession();
session.beginTransaction(); Query query = session.createQuery(hql);
//query.setCacheable(true);//手动开启查询缓存
rtnStrs =(List<String>) query.list(); session.getTransaction().commit();
} catch (Exception e){
System.out.println("DAO层根据HQL语句查询失败");
}
return rtnStrs;
}

上面代码中屏蔽了query.setCacheable(true)。

关闭二级缓存、关闭查询缓存 运行如下:

开启查询缓存、关闭二级缓存运行如下

结论:对于查询普通属性,无论二级缓存是否开启,只要开启了查询缓存,当两次执行的sql语句相同时,第二次不会发出sql语句,直接从内存中获取。

2、查询缓存开启时,二级缓存打开和关闭情况对比*******查询实体对象

/**
* 查询缓存开启,二级缓存关闭*******查询实体对象
*
*运行结果:如果关闭查询缓存和二级缓存,在两次查询时都发出sql语句,此时为两条查询语句
*
*运行结果:如果开启查询缓存,关闭二级缓存,第二次会发出根据ID查询实体的n条查询语句
*
*运行结论:第一次执行list时,会把查询对象的ID缓存到查询缓存中,第二次执行list时(两次的查询SQL语句相同),会遍历查询缓存中的ID到
* (一级、二级)缓存里找实体对象, 此时没有,则发出查询语句到数据库中查询
*
*/
publicString mycache3() {
List<User>users1 = this.userServiceImpl.search();
for(User u : users1) {
System.out.println("users1:username:"+ u.getUsername());
}
System.out.println("==============="); List<User> users2 =this.userServiceImpl.search();
for (User u : users2) {
System.out.println("users2:usersname:" + u.getUsername());
}
return"/mycache";
}

开启查询缓存、关闭二级缓存 运行如下:(两次都发出sql,而且第二次发出n条语句)

开启查询缓存、关闭二级缓存 运行如下(只发出一条语句)

总结:

(1)、当只是用hibernate查询缓存,而关闭二级缓存的时候:

①如果查询的是部分属性结果集,那么当第二次查询的时候就不会发出SQL语句,直接从Hibernate查询缓存中取数据

②如果查询的是实体结果集(eg.from User)这个HQL,那么查询出来的实体,首先hibernate查询缓存存放实体的ID,第二次查询的时候,就到hibernate查询缓存中取出ID一条一条的到数据库查询,这样将发出N条SQL语句,造成SQL泛滥。所以,在使用查询缓存的时候,最好配合开启二级缓存。

(2)、当开启Hibernate查询缓存和二级缓存的时候:

①如果查询的是部分属性结果集,这个和上面只用hbiernate查询缓存而关闭二级缓存的时候一致,因为不涉及实体,不会用到二级缓存。

②如果查询的是实体结果集,那么查询出来的实体首先在查询缓存中存放实体的ID,并将实体对象保存到二级缓存中,第二次查询的时候,就到hibernate查询缓存中取ID,根据ID去二级缓存中匹配数据,如果有数据就不会发出sql语句,如果都有,第二次查询一条SQL语句都不会发出,直接从二级缓存中取数据。

通过Javamelody

JavaMelody能够在运行环境中监测Java或Java EE应用程序服务器。并以图表的形式显示:Java内存和Java CPU使用情况,用户Session数量,JDBC连接数,和http请求、sql请求、jsp页面与业务接口方法(EJB3、Spring、Guice)的执行数量,平均执行时间,错误百分比等。

坤哥博客有介绍Java项目性能监控和调优工具-Javamelody

监控项目缓存个数

这是本次开发的权限项目中的缓存,共有12个,其中红色部分分别为二级缓存和查询缓存

对spring的监控

加缓存情况

不加缓存情况

根据统计结果,发现缓存的确可以提高性能。

但是有时候使用了缓存反而性能会降低,比如update方法,因为数据发生变更后,hibernate需要保持缓存和数据库两份的数据同步,所以加上缓存后,update性能降低,add、delete操作也是相同的道理。

所以缓存适用于在项目中存在大量查询的情况,否则是没必要适用的。

小结

在想项目之所以很吸引自己,很重要的一点是因为我们在使用各种各样的工具,包括在此提到的缓存、javamelody,正如“君子生非异也,善假于物也”,更多工具的使用,会在后面详细介绍。

性能优化之Hibernate缓存讲解、应用和调优的更多相关文章

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

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

  2. Hibernate性能优化之EHCache缓存

    像Hibernate这种ORM框架,相较于JDBC操作,需要有更复杂的机制来实现映射.对象状态管理等,因此在性能和效率上有一定的损耗. 在保证避免映射产生低效的SQL操作外,缓存是提升Hibernat ...

  3. [MySQL性能优化系列]提高缓存命中率

    1. 背景 通常情况下,能用一条sql语句完成的查询,我们尽量不用多次查询完成.因为,查询次数越多,通信开销越大.但是,分多次查询,有可能提高缓存命中率.到底使用一个复合查询还是多个独立查询,需要根据 ...

  4. 梁敬彬老师的《收获,不止SQL优化》,关于如何缩短SQL调优时间,给出了三个步骤,

    梁敬彬老师的<收获,不止SQL优化>,关于如何缩短SQL调优时间,给出了三个步骤, 1. 先获取有助调优的数据库整体信息 2. 快速获取SQL运行台前信息 3. 快速获取SQL关联幕后信息 ...

  5. SQL性能优化前期准备-清除缓存、开启IO统计

    文章来至:https://www.cnblogs.com/Ren_Lei/p/5669662.html 如果需要进行SQl Server下的SQL性能优化,需要准备以下内容: 一.SQL查询分析器设置 ...

  6. 秋色园QBlog技术原理解析:性能优化篇:缓存总有失效时,构造持续的缓存方案(十四)

    转载自:http://www.cyqdata.com/qblog/article-detail-38993 文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文 ...

  7. OpenStack入门篇(五)之KVM性能优化及IO缓存介绍

    1.KVM的性能优化,介绍CPU,内存,IO性能优化 KVM CPU-->qemu进行模拟ring 3-->用户应用 (用户态,用户空间)ring 0-->操作系统 (内核态,内核空 ...

  8. MySQL数据库的性能分析 ---图书《软件性能测试分析与调优实践之路》-手稿节选

    1  .MySQL数据库的性能监控 1.1.如何查看MySQL数据库的连接数 连接数是指用户已经创建多少个连接,也就是MySQL中通过执行 SHOW  PROCESSLIST命令输出结果中运行着的线程 ...

  9. Hibernate 性能优化之一级缓存

     1.一级缓存的生命周期     一级缓存在session中存放,只要打开session,一级缓存就存在了,当session关闭的时候,一级缓存就不存在了   2.一级缓存是依赖于谁存在的      ...

随机推荐

  1. 【转】手机web——自适应网页设计(html/css控制)

    手机web——自适应网页设计(html/css控制) 就目前形势来看,Web App 正是眼下的一个趋势和潮流,但是,对于Web App的设计可能大家有的不是很了解,下面就将整理好的网页设计的技巧奉献 ...

  2. PHP批量审核ajax jquery

    var jQuery = $.noConflict(); // alert(jQuery); jQuery(document).ready(function() { /*批量审核*/ jQuery(' ...

  3. Cookie知识点小结

    问题是什么?有哪些技术?如何解决? 1. Cookie 1)完成回话跟踪的一种机制:采用的是在客户端保存Http状态信息的方案 2)Cookie是在浏览器访问WEB服务器的某个资源时,由WEB服务器在 ...

  4. Apache POI组件操作Excel,制作报表(二)

    本文接上一篇继续探究POI组件的使用.     现在来看看Excel的基本设置问题,以2007为例,先从工作簿来说,设置列宽,因为生成表格列应该固定,而行是遍历生成的,所以可以在工作簿级别来设置列宽, ...

  5. Prototypes analyze(二叉排序树,不同树形个数)

    Prototypes analyze 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 ALpha Ceiling Manufacturers (ACM) is ana ...

  6. RDBMS 数据库补丁集补丁号码高速參考-文档 ID 1577380.1

    保存此文,高速查询补丁号 Oracle Database - Enterprise Edition - 版本号 8.1.7.0 和更高版本号 本文档所含信息适用于全部平台 补丁集/PSU 补丁号码   ...

  7. 传输中文乱码js解决方法

    encodeURI要编码两次 var a="我的"; //编译两次 //window.location.href = "http://127.0.0.1:8080/kab ...

  8. Java中遍历Map对象的方法

    方法一: 在for-each循环中使用entries来遍历 这是最常见的遍历方式,在需要获取key和value时使用. Map<Integer, Integer> map = new Ha ...

  9. JS实现下拉框选中不同的项,对应显示不同的信息

    实现的效果如下图: 页面代码 下拉框: <select id="select3" name="select3" onchange="showli ...

  10. FOR UPDATE SKIP LOCKED

    SYS_UNIT 中有UNIT_ID 0000000001 0000000002 0000001100 原意为若启用多线程,则每个线程在获取时仅可以获取一条数据(互斥) 脚本如下 1.SELECT * ...