当前访客身份:游客 [ 登录  | 注册加入尚学堂]
启用新域名sxt.cn
新闻资讯

hibernate抓取策略,batch-size的用法

我来了! 发表于 2年前  | 评论(0 )| 阅读次数(699 )|   0 人收藏此文章,   我要收藏
摘要 hibernate抓取策略,batch-size的用法

hibernate抓取策略,,batch-szie在<class>上的应用

batch-size属性,可以批量加载实体类。

MyClass.hbm.xml

 
    <?xml version="1.0"?>  
    <!DOCTYPE hibernate-mapping PUBLIC  
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">  
      
    <hibernate-mapping package="com.org.model">  
        <class name="MyClass" table="class" batch-size="3">  
            <id name="id">  
                <generator class="native"/>  
            </id>  
            <property name="name" not-null="true"/>  
              
            <!-- set标签中的name为MyClass类中多方对应的属性名        key标签中的column为多方数据库表中的外键字段-->  
            <set name="students"  cascade="save-update" inverse="true">  
                <key column="class_id" not-null="true"></key>  
                  
                <one-to-many class="Student"/>      <!-- class表明set中放的是什么类型的集合 -->  
            </set>  
        </class>  
      
      
    </hibernate-mapping>   

 Student.hbm.xml

 
    <?xml version="1.0"?>  
    <!DOCTYPE hibernate-mapping PUBLIC  
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">  
      
    <hibernate-mapping package="com.org.model">  
        <class name="Student" table="student">  
            <id name="id">  
                <generator class="native"/>  
            </id>  
            <property name="name" column="name" not-null="true"/>  
              
            <!--   name指Student类中对应一方的属性名          cascade属性指定级联操作           
             class指一方的类名                column中的name表示关联的外键        
             not-null表示此外键不能为空    -->   
              
            <many-to-one name="classes"  class="MyClass" cascade="save-update">  
                   <column name="class_id" not-null="true"></column>  
            </many-to-one>  
        </class>  
      
      
    </hibernate-mapping>   

 

测试用例:
   

 
    List<Student> students = session.createQuery("from Student s where s.id in (:ids) ")  
                  
                     .setParameterList("ids", new Object[]{43,46}).list();  
                  
                      Iterator<Student> iterator = students.iterator();  
        while(iterator.hasNext()){  
                      
                          Student student = iterator.next();  
                      
                          System.out.println("学生姓名:"+student.getName());  
                      
                          System.out.println("该学生所在班级"+student.getClasses().getName());  
                }   

  

 

1)若没配batch-size,即<class name="MyClass" table="class">

执行结果:总共执行三条查询语句,其中执行1条学生查询语句,2条班级查询语句

 
    Hibernate: select student0_.id as id1_, student0_.name as name1_, student0_.class_id as class3_1_ from student student0_ where student0_.id in (? , ?)  
      
    学生姓名:ccc  
    Hibernate: select myclass0_.id as id0_0_, myclass0_.name as name0_0_ from class myclass0_ where myclass0_.id=?  
    该学生所在班级09003  
      
    学生姓名:aaa  
    Hibernate: select myclass0_.id as id0_0_, myclass0_.name as name0_0_ from class myclass0_ where myclass0_.id=?  
    该学生所在班级09004   

 

2)若配batch-size,即<class name="MyClass" table="class" batch-size="3">

执行结果:总共执行2跳查询语句,其中执行1条学生查询语句,执行1条班级查询语句(每3个班级,发一条sql语句)

 
    Hibernate: select student0_.id as id1_, student0_.name as name1_, student0_.class_id as class3_1_ from student student0_ where student0_.id in (? , ?)  
      
    学生姓名:ccc  
    Hibernate: select myclass0_.id as id0_0_, myclass0_.name as name0_0_ from class myclass0_ where myclass0_.id in (?, ?)  
      
    该学生所在班级09003  
    学生姓名:aaa  
    该学生所在班级09004   

 

hibernate抓取策略,batch-szie在集合上的应用


batch-size属性,可以批量加载实体类,
<set name="students" batch-size="3">

 MyClass.hbm.xml

 
    <strong><?xml version="1.0"?>  
    <!DOCTYPE hibernate-mapping PUBLIC  
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">  
      
    <hibernate-mapping package="com.org.model">  
        <class name="MyClass" table="class" >  
            <id name="id">  
                <generator class="native"/>  
            </id>  
            <property name="name" not-null="true"/>  
              
            <!-- set标签中的name为MyClass类中多方对应的属性名        key标签中的column为多方数据库表中的外键字段-->  
            <set name="students"  cascade="save-update" inverse="true" batch-size="3">  
                <key column="class_id" not-null="true"></key>  
                  
                <one-to-many class="Student"/>      <!-- class表明set中放的是什么类型的集合 -->  
            </set>  
        </class>  
      
      
    </hibernate-mapping></strong>   

 

测试用例:


List<MyClass> classes = session.createQuery("from MyClass ").list();  
              
          Iterator<MyClass> iterator1 = classes.iterator();  
              
          while(iterator1.hasNext()){  
                  
                 MyClass class1 = iterator1.next();  
                  
                 System.out.println("班级名:" + class1.getName());  
  
                  
                 Set<Student> students = class1.getStudents();  
                  
                 System.out.println("班级人数:" + students.size());  
                  
                if (students != null && !students.isEmpty()) {  
                      
                        Iterator<Student> iterator = students.iterator();  
                      
                          System.out.print("学生姓名:");  
                      
                         while (iterator.hasNext()) {  
                          
                                Student student = iterator.next();  
                        System.out.println(student.getName());  
                    }  
                }  
                  
            }


  

1)若配batch-size,即:<set name="students" batch-size="3"> 使用set的batch-size属性,这个属性可以明显的减少执行SQL语句数目,因为它执行的是这样的语句:
如果batch-size=10,而集合有13个关联对象,那么它会执行如下语句:
select id,... from table where id in (?,?,?,?,?,?,?,?,?,?)
select id,... from table where id in (?,?,?)
总共2条语句,如果不设置batch-size,就要执行13条SQL语句

执行结果:总共执行2条sql语句,1条班级查询语句,总共三个关联集合或对象,所以1条关联对象查询语句

 
Hibernate: select myclass0_.id as id0_, myclass0_.name as name0_ from class myclass0_  
  
班级名:09002  
Hibernate: select students0_.class_id as class3_0_1_, students0_.id as id1_,   
students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student students0_ where students0_.class_id in (?, ?, ?)  
班级人数:0  
班级名:09003  
班级人数:3  
学生姓名:bbb  
ccc  
aaa  
班级名:09004  
班级人数:3  
学生姓名:aaa  
ccc  
bbb   

 1)若不配batch-size,即:<set name="students">

执行结果:

 

 
Hibernate: select myclass0_.id as id0_, myclass0_.name as name0_ from class myclass0_  
  
班级名:09002  
Hibernate: select students0_.class_id as class3_0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student students0_ where students0_.class_id=?  
班级人数:0  
  
班级名:09003  
Hibernate: select students0_.class_id as class3_0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student students0_ where students0_.class_id=?  
班级人数:3  
学生姓名:ccc  
aaa  
bbb  
  
班级名:09004  
Hibernate: select students0_.class_id as class3_0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student students0_ where students0_.class_id=?  
班级人数:3  
学生姓名:ccc  
aaa  
bbb   

 

hibernate.jdbc.fetch_size 和 hibernate.jdbc.batch_size

hibernate.jdbc.fetch_size 50 //读

hibernate.jdbc.batch_size 30 //写

 hiberante.cfg.xml(Oracle ,sql server 支持,mysql不支持)

 
    <property name="hibernate.jdbc.fetch_size">50</property>  
    <property name="hibernate.jdbc.batch_size">30</property>   


这两个选项非常非常非常重要!!!将严重影响Hibernate的CRUD性能!

 

C = create, R = read, U = update, D = delete

 

Fetch Size 是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数。

 

例如一次查询1万条记录,对于Oracle的JDBC驱动来说,是不会1次性把1万条取出来的,而只会取出Fetch Size条数,当纪录集遍历完了这些记录以后,再去数据库取Fetch Size条数据。因此大大节省了无谓的内存消耗。当然Fetch Size设的越大,读数据库的次数越少,速度越快;Fetch Size越小,读数据库的次数越多,速度越慢。这有点像平时我们写程序写硬盘文件一样,设立一个Buffer,每次写入Buffer,等Buffer满了以后,一次写入硬盘,道理相同。

 

Oracle数据库的JDBC驱动默认的Fetch Size=10,是一个非常保守的设定,根据我的测试,当Fetch Size=50的时候,性能会提升1倍之多,当Fetch Size=100,性能还能继续提升20%,Fetch Size继续增大,性能提升的就不显著了。

 

因此我建议使用Oracle的一定要将Fetch Size设到50

 

不过并不是所有的数据库都支持Fetch Size特性,例如MySQL就不支持

 

MySQL就像我上面说的那种最坏的情况,他总是一下就把1万条记录完全取出来,内存消耗会非常非常惊人!这个情况就没有什么好办法了 :(

 

Batch Size是设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小,有点相当于设置Buffer缓冲区大小的意思。

 

Batch Size越大,批量操作的向数据库发送sql的次数越少,速度就越快。我做的一个测试结果是当Batch Size=0的时候,使用Hibernate对Oracle数据库删除1万条记录需要25秒,Batch Size = 50的时候,删除仅仅需要5秒!!!

分享到:0
关注微信,跟着我们扩展技术视野。每天推送IT新技术文章,每周聚焦一门新技术。微信二维码如下:
微信公众账号:尚学堂(微信号:bjsxt-java)
声明:博客文章版权属于原创作者,受法律保护。如果侵犯了您的权利,请联系管理员,我们将及时删除!
(邮箱:webmaster#sxt.cn(#换为@))
北京总部地址:北京市海淀区西三旗桥东建材城西路85号神州科技园B座三层尚学堂 咨询电话:400-009-1906 010-56233821
Copyright 2007-2015 北京尚学堂科技有限公司 京ICP备13018289号-1 京公网安备11010802015183