Hibernate性能优化

性能优化

1、Session.clear()的应用

不断分页循环的时候,使用clear()方法。

Java中的内存泄漏:

如果使用java打开某一个资源后,一定要关闭,否则就有可能导致内存泄漏。比如:使用java打开一个文件,实际上是java调用了C,C调用了windows底层的API,如果不手动将资源关闭,C语言必须手动回收内存,这就导致了有java引起的内存泄漏。

2、1+N问题

(1)使用@ManyToOne的时候,默认FetchType=EAGER,此时会自动取出One这一方的信息。

(2)解决方法:

a) 将FetchType设置为Lazy。这种方式在One这一方被使用到的时候,才会发出SQL语句

b) 在对应的类上加上@BatchSize,这样会在发出SQL语句,以下取出N条One这一方的信息。(其实没有解决,只是减少了SQL语句的条数)

c) 在HQL语句中,使用join fetch 进行查询。或者使用QBC语句进行查询

实验:

(1)默认的ManyToOne的FetchType为EAGER

// N+1

@Test

public void testQuery1() {

Session session = sf.openSession();

session.beginTransaction();

List<Topic> topics = (List<Topic>) session.createQuery("from Topic")

.list();// 如果此时不设置FetchType=LAZY,则会默认取出Category中的id属性

for(Topic t : topics) {

System.out.println(t.getId() + "-" + t.getTitle());

}

session.getTransaction().commit();

session.close();

}

查看生成的SQL语句如下:

Hibernate:

select

topic0_.id as id1_2_,

topic0_.category_id as category4_2_,

topic0_.createDate as createDa2_2_,

topic0_.title as title3_2_

from

Topic topic0_

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

1-t0

2-t1

3-t2

4-t3

5-t4

6-t5

7-t6

8-t7

9-t8

10-t9

结论:

默认的FetchType会导致自动获取One一方的属性。

(2)解决方法1:

将FetchType设置为LAZY

@ManyToOne(fetch=FetchType.LAZY)

再次观察生成的结果SQL语句:

Hibernate:

select

topic0_.id as id1_2_,

topic0_.category_id as category4_2_,

topic0_.createDate as createDa2_2_,

topic0_.title as title3_2_

from

Topic topic0_

1-t0

2-t1

3-t2

4-t3

5-t4

6-t5

7-t6

8-t7

9-t8

10-t9Hibernate:

select

topic0_.id as id1_2_,

topic0_.category_id as category4_2_,

topic0_.createDate as createDa2_2_,

topic0_.title as title3_2_

from

Topic topic0_

1-t0

2-t1

3-t2

4-t3

5-t4

6-t5

7-t6

8-t7

9-t8

10-t9

结论:

可以实现预期结果,但是,当FetchType为LAZY的时候,并不是不会发出查询One这一边的信息的SQL语句,而是在用到One这一方信息的时候,才会发出SQL语句。

(3)解决方法2:

使用@BatchSize(size=n)的形式控制SQL语句执行的次数。

使用如上形式,可以一次性取出n条one这一方的数据,这样就减少了每条数据都会查询One这一方的信息的SQL查询,

测试:

在Category也就是One这一方加入@BatchSize(size=5)

再次运行以上测试程序:

Hibernate:

select

topic0_.id as id1_2_,

topic0_.category_id as category4_2_,

topic0_.createDate as createDa2_2_,

topic0_.title as title3_2_

from

Topic topic0_

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id in (

?, ?, ?, ?, ?

)

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id in (

?, ?, ?, ?, ?

)

1-t0

2-t1

3-t2

4-t3

5-t4

6-t5

7-t6

8-t7

9-t8

10-t9

观察结果:此时关于One这一方的查询操作只做了两次,因为总共有10条数据,每次查询5条,2次就查询完了。

结论:

以上做法只是减少了SQL语句的发出,并没有从根本上解决1+N问题。

(4)解决方法3:

在QL中使用join fetch

测试方法改成如下形式:

//join fetch

@Test

public void testQuery4() {

Session session = sf.openSession();

session.beginTransaction();

List<Topic> topics =

(List<Topic>)session.createQuery("from Topic t left join fetch t.category c").list();

for(Topic t : topics) {

System.out.println(t.getId() + "-" + t.getTitle());

// System.out.println(t.getCategory().getName());

}

session.getTransaction().commit();

session.close();

}

查看执行的SQL语句:

Hibernate:

select

topic0_.id as id1_2_0_,

category1_.id as id1_0_1_,

topic0_.category_id as category4_2_0_,

topic0_.createDate as createDa2_2_0_,

topic0_.title as title3_2_0_,

category1_.name as name2_0_1_

from

Topic topic0_

left outer join

Category category1_

on topic0_.category_id=category1_.id

1-t0

2-t1

3-t2

4-t3

5-t4

6-t5

7-t6

8-t7

9-t8

10-t9

结论:

此方法可以达到预期的效果,在使用到One一方的数据的时候,会发出SQL语句进行查询操作。

3、list_iterate

(1)list()方法直接取出所需要的对象。在同一个Session中,如果有两个list()方法,将会指定两次list操作,每条数据会发出两条SQL语句。list()方法不会使用session级别的缓存

(2)iterate()方法会取出对应的id值,当使用到该对象的属性的时候,才会根据id值去查找所需要的值。iterate()方法会使用session中的缓存,当再次查询的时,就可以直接从缓存中查找,当session中没有的时候,会再次查询并发出SQL语句。

(3)当使用的时候,可以先使用list()方法,再次使用的时候,可以选择iterator()进行查询

测试:

package com.zgy.hibernate.model;

import java.util.Date;

import java.util.Iterator;

import java.util.List;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.AnnotationConfiguration;

import org.hibernate.cfg.Configuration;

import org.hibernate.tool.hbm2ddl.SchemaExport;

import org.junit.AfterClass;

import org.junit.BeforeClass;

import org.junit.Test;

public class HibernateQLTest {

private static SessionFactory sf;

@BeforeClass

public static void beforeClass() {

sf = HibernateUtil.getSessionFactory();

}

@AfterClass

public static void afterClass() {

sf.close();

}

@Test

public void testSchemaExport() {

new SchemaExport(new Configuration().configure()).create(true,true);

}

@Test

public void testSave() {

Session session = sf.openSession();

session.beginTransaction();

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

Category c = new Category();

c.setName("c" + i);

Topic t = new Topic();

t.setCategory(c);

t.setTitle("t" + i);

t.setCreateDate(new Date());

session.save(c);

session.save(t);

}

session.getTransaction().commit();

session.close();

}

//join fetch

@Test

public void testQueryList() {

Session session = sf.openSession();

session.beginTransaction();

//List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();

List<Category> categories = (List<Category>)session.createQuery("from Category").list();//同一个session中的第一个list()

for(Category c : categories) {

System.out.println(c.getName());

}

List<Category> categories2 = (List<Category>)session.createQuery("from Category").list();//同一个session中的第二个list()

for(Category c : categories2) {

System.out.println(c.getName());

}

session.getTransaction().commit();

session.close();

}

//join fetch

@Test

public void testQueryIterate() {

Session session = sf.openSession();

session.beginTransaction();

//List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();

Iterator<Category> categories = (Iterator<Category>)session.createQuery("from Category").iterate();//同一个Session中的第一个iterate

while(categories.hasNext()) {

Category c = categories.next();

System.out.println(c.getName());

}

Iterator<Category> categories2 = (Iterator<Category>)session.createQuery("from Category").iterate();//同一个session中的第二个iterate()

while(categories2.hasNext()) {

Category c = categories2.next();

System.out.println(c.getName());

}

session.getTransaction().commit();

session.close();

}

public static void main(String[] args) {

beforeClass();

}

}

观察运行结果:

testList()方法测试完后产生的SQL语句如下:

Hibernate:

select

category0_.id as id1_0_,

category0_.name as name2_0_

from

Category category0_

c0

c1

c2

c3

c4

c5

c6

c7

c8

c9

Hibernate:

select

category0_.id as id1_0_,

category0_.name as name2_0_

from

Category category0_

c0

c1

c2

c3

c4

c5

c6

c7

c8

c9

testIterate()方法测试完后产生的SQL语句:

Hibernate:

select

category0_.id as col_0_0_

from

Category category0_

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

c0

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

c1

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

c2

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

c3

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

c4

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

c5

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

c6

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

c7

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

c8

Hibernate:

select

category0_.id as id1_0_0_,

category0_.name as name2_0_0_

from

Category category0_

where

category0_.id=?

c9

Hibernate:

select

category0_.id as col_0_0_

from

Category category0_

c0

c1

c2

c3

c4

c5

c6

c7

c8

c9

时间: 2024-10-18 16:25:05

Hibernate性能优化的相关文章

Hibernate性能优化之EHCache缓存

像Hibernate这种ORM框架,相较于JDBC操作,需要有更复杂的机制来实现映射.对象状态管理等,因此在性能和效率上有一定的损耗. 在保证避免映射产生低效的SQL操作外,缓存是提升Hibernate的关键之一. 加入缓存可以避免数据库调用带来的连接创建与销毁.数据打包拆包.SQL执行.网络传输,良好的缓存机制和合理的缓存模式能带来性能的极大提升,EHCache就提供了这种良好的缓存机制. 在考虑给系统加入缓存进行优化前,复用SessionFactory是Hibernate优化最优先.最基础的

8.Hibernate性能优化

性能优化 1.注意session.clear() 的运用,尤其在不断分页的时候 a) 在一个大集合中进行遍历,遍历msg,取出其中额含有敏感字样的对象 b) 另外一种形式的内存泄漏( //面试题:Java有内存泄漏吗?语法级别没有,但是可由java引起,例如:连接池不关闭,或io读取后不关闭) 2.1+N 问题(典型的面试题) 举例:当存在多对一关系时,多的一方默认是可以取出一的一方的 @ManyToOne 中 默认为fetch=FetchType.Eager 当load多的一方时,也会加载一的

Hibernate性能优化之SessionFactory重用

Hibernate优化的方式有很多,如缓存.延迟加载以及与SQL合理映射,通过对SessionFactory使用的优化是最基础的. SessionFactory负责创建Session实例,Session相当于JDBC里的Connection. SessionFactory的创建 SessionFactory是通过Configuration来构建的,Configuration会根据配置信息来构建SessionFactory. SessionFactory中保存了对应当前数据库配置的所有映射关系,还

Hibernate 性能优化及缓存的使用

1 clear()方法的运用: 由于hibernate在查询出来数据之后,会把数据进行缓存,对于同一个session多次大数据的查询,由于缓存会占用一定的内存空间,因此要多用seesion.clear(0方法清空缓存: 2 对于多发的sql语句合理设置tetch: 在关联查询时候,有时候只查询其中一个表里的数据,而hibernate会发出多条sql语句把另外一张表的数据也进行查询,影响性能,可以通过设置fetch的值来进行关联查询时候的懒加载:例如在多对一查询时候 @ManyToOne(casc

第七章 Hibernate性能优化

一对一关联 实体类关系 一对多 多对多 一对一 Hibernate提供了两种映射一对一关联关系的方式:按照外键映射和按照主键映射.下面以员工账号和员工档案表为例,介绍这两种映射方式,并使用这两种映射方式分别完成以下持久化操作: (1)保存员工档案的同时分配给员工一个账号. (2)加载员工档案的同时加载账号信息. 1.按照外键映射 步骤一:创建实体类Users1和Resume1 Users1创建如下: public class Users1 { private Integer userid; pr

Hibernate 性能优化之抓取策略

fetch 抓取策略 前提条件:必须是一个对象操作其关联对象. 1. 根据一的一方加载多的一方,在一的一方集合中,有三个值:join/select/subselect 2.根据多的一方加载一的一方, 这种情况不考虑,因为关联对象就一个数据,怎么样都可以join 连接  [一次性的把两张表的数据全部查询出来,只发出一条sql语句]    *  在页面上既包括一的一方的数据,又包括多的一方的数据    *  数据库的数据量比较小select 默认的查询方式    [先加载classes,当得到stu

Hibernate 性能优化之懒加载

针对数据库中的大数据,不希望特别早的加载到内存中,当用到它的时候才加载 懒加载分为:类的懒加载.集合的懒加载.单端关联的懒加载 类的懒加载    1.在默认情况下,类就是执行懒加载        2.只有使用了load方法以后才能用懒加载    3.如果在相应的映射文件中,设置<class>的lazy="false"懒加载将失去效果集合的懒加载     1.针对一多对的情况或者多对多的情况    2.根据一方加载set集合,决定在什么时候给set集合填充数据        

Hibernate 性能优化之查询缓存

查询缓存是建立在二级缓存基础之上的,所以与二级缓存特性相似,是共享的,适合修改不是很频繁的数据 查询缓存不是默认开启的,需要设置      1.在cfg文件中配置 <property name="cache.use_query_cache">true</property> 2.在代码中进行设置 query.setCacheable(true);

hibernate之性能优化

hibernate是建立在JDBC基础上的框架,但他有很多JDBC所无法比拟的性能优化技术.下面介绍几种优化策略. 1.使用dynamic-insert与dynamic-update 在class标签中使用该属性,可以设置hibernate动态的生成SQL语句,而不是在hibernate启动时就生成预设的SQL语句. 当其设置为true时,hibernate会根据实际需求设置新增或更新的字段,而不是所有的字段. <class name="com.hibernate.book" t