`

Hibernate性能优化策略

阅读更多
  使用乐观锁在表中加一个version的字段来解决并发性问题

  悲观锁:就是多个人同时想修改某个数据,

  第一个人读出数据,数据库就锁定了其他人对该数据的修改和删除,

  但允许其它人查询该数据,直到第一个人提交保存后其它人才能修改,

  否则其它人在提交时系统会一直等待第一个人完成提交

  乐观锁:乐观锁需要在表中加一version(版本)字段,并要在对应的类中配置

  就是多个人同时想修改某个数据,如果多人同时读出数据,那么他们的版本号都相同比如是1,

  然后其中有一个人最先提交了修改,那么表中版本字段会自动加一,

  当其它人提交时hibernat会自动判断自己的版本号是否与数据库中的版本号相同,

  如果低于数据库中的版本号那么就不允许提交。

  (如果是使用jdbc开发那么用户也要自己写个判断代码进行对版本号的判断)

  采用hibernate_session代码测试:

  一级缓存(用hibernate_one-to-many代码测试)

  1、一级缓存很短,和session的生命周期一致,随着session的关闭而消失

  *load/get/iterate(查询实体对象)可以使用缓存数据

  2、一级缓存它缓存的是实体对象

  3、如果管理缓存,如session.clear()/session.evict()

  4、如何避免一次性大批量实体数据插入内存溢出的问题?

  *先执行flush,在用clear清除缓存

  //发出两次load()第一次发一条sql第二次不发,说明它是先在一级缓存找数据,如果没有再到数据库找。

  /**

  * 发出两次load查询

  *

  */

  Student student = (Student)session.load(Student.class, 1);

  System.out.println("学生姓名:" + student.getName());

  //因为有一级缓存,load方法使用一级缓存,所以本次查询不再发出sql

  student = (Student)session.load(Student.class, 1);

  System.out.println("学生姓名:" + student.getName());

  -------------------------------------------------------------------------------------------

  //发出两次get() 同上

  /**

  * 发出两次get查询

  *

  */

  Student student = (Student)session.get(Student.class, 1);

  System.out.println("学生姓名:" + student.getName());

  //因为有一级缓存,get方法使用一级缓存,所以本次查询不再发出sql

  student = (Student)session.get(Student.class, 1);

  System.out.println("学生姓名:" + student.getName());

  --------------------------------------------------------------------------------------------

  /**

  * 发出两次iterate查询实体对象

  *

  */

  public void testCache3() {

  Session session = null;

  try {

  session = HibernateUtils.getSession();

  Student student = (Student)session.createQuery("from Student where id=1").iterate().next();

  System.out.println("学生姓名:" + student.getName());

  //因为有一级缓存,iterate方法使用一级缓存,发出查询id的sql,不再发出查询实体对象的sql

  student = (Student)session.createQuery("from Student where id=1").iterate().next();

  System.out.println("学生姓名:" + student.getName());

  //发出两次iterate查询实体对象

  (iterate 会有n+1问题,如果缓存有发查id那1条)

  先从数据库查出所有id,再根据ID查数据,所以会有n+1问题,但查实体对象会先在一级缓存查找。

sql:from student

  (实体对象就是说查询的不是单个或多个属性查询,而是整个对象,只要你不指定查询属性那就是实体对象)

  第一次发两条,有一条查ID,有一条查数据

  第二次发一条,只有查ID那条,说明查数据(就是查实体对像)也是先在缓存里找。

  //发出两次iterate查询单个或多个属性 sql:select name from student where id=1

  //它每次都会发sql说明它不使用一级缓存,只使用查询缓存

  ------------------------------------------------------------------------------------------------

  /**

  * 发出两次iterate查询普通属性

  *

  */

  String name = (String)session.createQuery("select name from Student where id=1").iterate().next();

  System.out.println("学生姓名:" + name);

  //Iterate查询普通结果集,一级缓存不会缓存,它也不会发出查询id的sql

  name = (String)session.createQuery("select name from Student where id=1").iterate().next();

  System.out.println("学生姓名:" + name);

  ----------------------------------------------------

  /**

  * 打开两次session,调用load测试

  *

  */

  public void testCache5() {

  Session session = null;

  try {

  session = HibernateUtils.getSession();

  Student student = (Student)session.load(Student.class, 1);

  System.out.println("学生姓名:" + student.getName());

  }catch(Exception e) {

  e.printStackTrace();

  }finally {

  HibernateUtils.closeSession(session);

  }

  //打开第二个session

  try {

  session = HibernateUtils.getSession();

  //会发出sql,session间是不能共享一级缓存数据的

  //因为它会伴随session的生命周期存在和消亡

  Student student = (Student)session.load(Student.class, 1);

  System.out.println("学生姓名:" + student.getName());

  }catch(Exception e) {

  e.printStackTrace();

  }finally {

  HibernateUtils.closeSession(session);

  }

  }

  -----------------------------------------------

  /**

  * 先执行save,再执行load进行测试

  *

  */

  session = HibernateUtils.getSession();

  session.beginTransaction();

  Student student = new Student();

  student.setName("张三");

  Serializable id = session.save(student);

  //因为save会将实体对象的数据缓存到session中

  //所以再次查询相同数据,不会发出sql

  Student newStudent = (Student)session.load(Student.class, id);

  System.out.println("学生姓名:" + newStudent.getName());

  session.getTransaction().commit();

  ---------------------------------------------------------------------------

  /**

  * 执行session.clear()或session.evict()方法后,再调用load

  */

  Student student = (Student)session.load(Student.class, 1);

  System.out.println("学生姓名:" + student.getName());

  //管理session缓存(一级缓存机制无法取消的,但可以管理缓存,如:clear,evict方法)

  session.evict(student);

  //session.clear();

  //发出sql,因为缓存中的student实体类,已经被逐出

  student = (Student)session.load(Student.class, 1);

  System.out.println("学生姓名:" + student.getName());


-------------------------------------------------------------------------

  public void testCache8() {

  Session session = null;

  try {

  session = HibernateUtils.getSession();

  session.beginTransaction();

  for (int i = 0; i < 10000; i++) {

  Student student = new Student();

  student.setName("Student_" + i);

  session.save(student);

  //每100条数据就强制session将数据持久化

  //同时清空缓存,以避免在大量的数据下,造成内存溢出

  if ( i % 100 == 0) {

  session.flush();

  session.clear();

  }

  }

  session.getTransaction().commit();

  }catch(Exception e) {

  e.printStackTrace();

  session.getTransaction().rollback();

  }finally {

  HibernateUtils.closeSession(session);

  }

  }

  ==============================================================================

  ==============================================================================

  二级缓存

  定义步骤:

  1、打开缓存,在hibernate.cfg.xm中加入:

  <property name="hibernate.cache.use_second_level_cache">true</property>

  2、指定缓存策略提供商,在hibernate.cfg.xm中加入:

  <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

  3、拷贝echcahe.xml到src下,可以针对不同的策略配置缓存

  4、指定那些类使用缓存(两种方式)

  * 在hibernate.cfg.xml

  * 在映射文件中

  二级缓存中存储的也是实体对象,他们都属于SessionFactory级别,

  是全局的,伴随SessionFactory的生命周期存在和消亡

  用打开两个session代码测试

  二级缓存只针对实体对象,不是实体对象它不会缓存

  建议少用。

  ehcache.jar+ehcache.xml拷到jar目录(ehcache.xml文件在hibernate包里有.)

  ehcache.xml这个配置文件在ehcache.jar包里本身有一个配置文件,但在用jbpm时会出错,所以要将这个拷到src或其它目录下

  在hibernate.hbm.xml中的配置代码:

  <!-- 是否启用二级缓存  -->

  <property name="hibernate.cache.use_second_level_cache">true</property>

  <!-- 设置缓存策略提供商 -->

  <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

  <class-cache class="com.bjsxt.hibernate.Student" usage="read-only"/>

  /**

  * 调用了次load,第一次调用完成后,清除sessionFactory中的二级缓存数据,

  * 再开启一个session,调用load

  *

  */

  public void testCache2() {

  Session session = null;

  try {

  session = HibernateUtils.getSession();

  Student student = (Student)session.load(Student.class, 1);

  System.out.println("学生姓名:" + student.getName());

  }catch(Exception e) {

  e.printStackTrace();

  }finally {

  HibernateUtils.closeSession(session);

  }

//管理二级缓存

  SessionFactory factory = HibernateUtils.getSessionFactory();

  factory.evict(Student.class);

  //打开第二个session

  try {

  session = HibernateUtils.getSession();

  //因为二级缓存已经被清空,所以本次查询将发出一条新的sql

  Student student = (Student)session.load(Student.class, 1);

  System.out.println("学生姓名:" + student.getName());

  }catch(Exception e) {

  e.printStackTrace();

  }finally {

  HibernateUtils.closeSession(session);

  }

  }

  ---------------------------------------------

  一级缓存与二级缓存的交互:

  用factory.cacheMode="get"

  ==============================================================================

  ==============================================================================

  查询缓存(只对.list()起作用,对iterate()不起作用)

  配置:

  在hibernate.cfg.xml文件中加入:<property name="hibernate.cache.use_query_cache">true</property>

  1、针对普通属性结果集的缓存

  2、对是实体对象的结果集,只缓存id

  3、使用查询缓存,需要打开查询缓存,并且在调用list方法之前需要显示的调用query.setCacheable(true);

  查询缓存的生命周期是由hibernate控制的,它的生命周期不一定,比如我查询了10条数据,但这10条数据在数据库中被别人修改了,那么查询缓存就会马上被清掉。如果查询缓存里有多个普通属性对像那么其中任何一个被修改查询缓存都会被清除

  一级与二级缓存是对实体对象的,查询缓存是对普通属性的。

  如果打开了查询缓存关闭二级缓存 查询实例对象测试第二次list.iterator也会产生n+1问题

  如果查询缓存与二级缓存同时打开 查询实例对象测试第二次list.iterator不会发出任何sql

  ================================================================================

  抓取策略:

  抓取策略是对延迟加载的优化

  可以配置在单端属性上(many-to-one和one-to-one)和集合属性上(<set>)。

  fetch="select"

  fetch="join"

  fetch="subselect"

  参见:hibernate_fetch_6

  拷贝hibernate_fetch1项目测试batch-size

  针对fetch="select"配置进行优化,加入batch,如:

  <class name="com.bjsxt.hibernate.Classes" table="t_classes" batch-size="5">

  批量抓取配置:Classes.hbm.xml中加:<class .....   batch-size="10">

  抓取策略使用默认,也就是fetch="select"

  public void testFetch1() {

  Session session = null;

  try {

  session = HibernateUtils.getSession();

  List students = session.createQuery("select s from Student s where s.id in(:ids)")

  .setParameterList("ids", new Object[]{1, 11, 21, 31, 41, 51, 61, 71, 81, 91})

  .list();

  for (Iterator iter = students.iterator(); iter.hasNext();) {

  Student student = (Student)iter.next();

  System.out.println("学生:" + student.getName());

  System.out.println("班级:" + student.getClasses().getName());

  }

  }catch(Exception e) {

  e.printStackTrace();

  }finally {

  HibernateUtils.closeSession(session);

  }

  }

  上面运行结果,如果不加batch-size="10"那么查询每个班都会发一条sql加了之后每查询10条才发一条sql

  参见:hibernate_fetch_7

  拷贝hibernate_fetch3项目测试(针对集合设置的batch-size)


分享到:
评论

相关推荐

    Hibernate性能优化研究.pdf

    ### Hibernate性能优化研究 #### 一、引言 随着企业级应用的发展,高效的数据持久化技术成为了提升系统性能的关键因素之一。Hibernate作为一种流行的面向Java环境的对象关系映射(Object-Relational Mapping,简称...

    Hibernate性能优化

    《Hibernate性能优化》 ...以上是Hibernate性能优化的一些核心点,实践中还需要结合具体项目进行调整和测试,找到最适合的优化策略。学习和理解这些知识点,有助于开发出更高效、更稳定的Java应用程序。

    hibernate性能优化方案

    综上所述,Hibernate性能优化涉及多个层面,包括但不限于数据库设计、HQL编写、API选择、配置参数调整、缓存管理、延迟加载以及事务控制策略等。通过对这些方面的综合考量和优化,可以极大地提升Hibernate应用程序的...

    Hibernate性能优化:一级缓存

    本文将深入探讨Hibernate性能优化中的一个重要概念——一级缓存,并结合给出的压缩包文件“hibernate_cache_level1”,来详细解析一级缓存的工作原理及其优化策略。 一级缓存是Hibernate内置的一种缓存机制,它存在...

    Hibernate性能优化共9页.pdf.zip

    "Hibernate性能优化共9页.pdf.zip" 这个文件标题表明了内容专注于Hibernate框架的性能优化,暗示我们将探讨如何提升使用Hibernate进行数据库操作时的效率。通常,性能优化涉及减少延迟、提高吞吐量、降低资源消耗等...

    hibernate性能优化.doc

    以下是一些关于Hibernate性能优化的关键点: 1. **数据库优化**: - **硬件优化**:磁盘I/O是数据库性能的关键,选择高速度、低寻道时间的磁盘可以显著提升读写速度。 - **配置文件优化**:针对MySQL,优化`my....

    Hibernate3性能优化 Hibernate_regerence3.12

    的效率低于直接JDBC存取,然而,在经过比较好的性能优化之后,Hibernate的性能还是让人相当满意的, 特别是应用二级缓存之后,甚至可以获得比较不使用缓存的JDBC更好的性能,下面介绍一些通常的 Hibernate的优化策略...

    Struts Spring Hibernate性能优化

    在进行大型项目开发时,性能优化是至关重要的,特别是对于基于SSH(Struts、Spring、Hibernate)这样的企业级框架的应用。SSH性能优化主要是针对Struts的MVC处理、Spring的依赖注入以及Hibernate的对象关系映射进行...

    Hibernate缓存,性能优化

    ### 性能优化策略 #### 合理利用缓存策略 - **一级缓存优化**:确保每个业务逻辑单元只在一个Session内完成,避免不必要的Session开启和关闭,减少一级缓存的刷新次数,从而提高性能。 - **二级缓存配置**:根据...

    hibernate-性能优化

    【标签】:hibernate, 性能优化 【正文】: 1. **数据库设计调整**: - **降低关联的复杂性**:减少多对多关联,避免过度嵌套的对象关系。 - **避免联合主键**:联合主键可能导致额外的性能损失,尝试使用单独的...

    hibernate性能优化[参考].pdf

    以下是对《hibernate性能优化[参考].pdf》内容的详细解读: 1. **数据库优化**: - **物理硬件优化**:关注磁盘的IO性能,因为数据库读写频繁,磁盘的寻道能力直接影响数据访问速度。 - **MySQL配置优化**:通过...

    Hibernate性能优化:二级缓存

    二级缓存是Hibernate性能优化的重要手段,通过合理配置和使用,可以显著减少数据库访问,提高系统响应速度。但同时,需要注意缓存的副作用,如数据一致性、并发控制等问题。在实际应用中,需要结合业务场景和性能...

    hibernate性能测试代码

    本话题将深入探讨“Hibernate性能测试代码”,以帮助我们理解如何有效地评估和优化Hibernate在实际应用中的表现。 首先,性能测试是软件开发过程中的关键环节,它旨在确定系统的响应时间、吞吐量和资源利用率等指标...

    Hibernate 性能优化

    ### Hibernate 性能优化 #### 一、引言 Hibernate 是一款非常强大的对象关系映射(ORM)框架,它能够简化 Java 应用程序与数据库之间的交互过程。然而,对于初次接触 Hibernate 的开发者来说,可能会遇到性能方面...

    Hibernate Quickly

    8. **性能优化**:探讨Hibernate性能优化策略,包括延迟加载(Lazy Loading)、批处理(Batch Processing)、缓存管理以及如何避免N+1查询问题。 9. **JPA支持**:由于Hibernate也是Java Persistence API(JPA)的...

Global site tag (gtag.js) - Google Analytics