zoukankan      html  css  js  c++  java
  • 【Hibernate框架】批量操作Batch总结

    在我们做.net系统的时候,所做的最常见的批量操作就是批量导入、插入、更新、删除等等,以前我们怎么做呢?基本上有以下几种方式:

    1、利用循环调用insert方法,一条条插入。

    1. public boolean insertStudent(List<Student> studentList)  
    2. {  
    3.     try{  
    4.         if(studentList.count !=0){  
    5.             for(int i=0;i<studentList.count;i++){  
    6.                 //调用save方法  
    7.             }  
    8.                 return true;  
    9.                 }  
    10.     }catch(Exception ex){  
    11.         throw New Exception("插入失败,请重试!")  
    12.         return false;  
    13.     }  
    14. }  




    2、利用循环做sql语句拼接,然后批量执行sql语句。

    1. public boolean insertStudent(List<Student> studentList)  
    2. {  
    3.     try{  
    4.         if(studentList.count !=0){  
    5.             stringBuffer strSqltxt="";  
    6.             for(int i=0;i<studentList.count;i++){  
    7.                 strSqltxt.append("insert into TableName (……) values (……);"  
    8.             }  
    9.             cmd.executesql(strSqltxt.toString());  
    10.         }  
    11.     }catch(Exception ex){  
    12.         throw New Exception("插入失败,请重试!")  
    13.         return false;  
    14.     }  
    15. }  



    可是,对于封装比较完善的hibernate持久层,我们又能怎么做呢?

           

           最常见的,也是利用循环来批量操作,但是,这里有一个必须要注意的点,就是缓存或者说是session区的空间是有限的,禁不起我们无限制的存放,所以,当我们执行以下操作时,会抛异常,内存溢出OutOfMemoryException!

    1. Session session = sessionFactory.openSession();  
    2. Transaction tx = session.beginTransaction();  
    3. for ( int i=0; i<100000; i++ ) {  
    4.     Customer customer = new Customer(.....);  
    5.     session.save(customer);  
    6. }  
    7. tx.commit();  
    8. session.close();  


    这样是不可以的,但是在这时,hibernate也给我们提供了解决方法,就是我们可以通过设置JDBC的批量抓去数量参数(batch size)来设置一个合适的值,比如说10-50-100不等,配置:

    1. <span style="font-size:18px;"><property name="hibernate.jdbc.batch_size">100</property></span>  

    另外,我们还可以显示的禁用二级缓存,以前我们也提到过:

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

    正确代码:

    1. Session session = sessionFactory.openSession();  
    2. Transaction tx = session.beginTransaction();  
    3. for ( int i=0; i<100000; i++ ) {  
    4.     Customer customer = new Customer(.....);  
    5.     session.save(customer);  
    6.     if(i%100==0){//100, 和配置的JDBC batch size一样  
    7.         session.fulsh();//刷出并同步到底层持久化, 批量的插入并且释放内存:  
    8.         session.clear(); //完全清除session  
    9.     }  
    10. }  
    11. tx.commit();  
    12. session.close();  

    这样就能解决我们的那个内存溢出的问题,因为当你的存储对象数超过你设定的能接受的合理值的时候,程序会自动将持久化对象flush进数据缓存起来,然后清空session,进行下一轮存储,待所有数据全部完成,执行commit进行提交,数据库更新数据,说的简单,这样的效率是不咋地的,不信你可以试试,你想想,先发出sql,100一轮,执行1000轮用来缓存sql语句,然后数据库统一执行sql,时间啊!

    StatelessSession(无状态session)接口

    但是这不是问题,因为hibernate还给我们提供了一个StatelessSession(无状态session)接口,作为选择,Hibernate提供了基于命令的API:

    1、可以用detached object(托管对象)的形式把数据以流的方法加入到数据库,或从数据库输出。

    2、StatelessSession没有持久化上下文,也不提供多少高层的生命周期语义。

    3、无状态session不实现第一级cache;

    4、也不和第二级缓存交互,也不和查询缓存交互。

    5、它不实现事务化写,也不实现脏数据检查。

    6、用stateless session进行的操作甚至不级联到关联实例。

    7、stateless session忽略集合类(Collections)。

    8、通过stateless session进行的操作不触发Hibernate的事件模型和拦截器。

    9、无状态session对数据的混淆现象免疫,因为它没有第一级缓存。

    10、无状态session是低层的抽象,和低层JDBC相当接近。换句话说,它可以直接操作数据。

    1. StatelessSession session = sessionFactory.openStatelessSession();  
    2. Transaction tx = session.beginTransaction();  
    3.      
    4. ScrollableResults customers = session.getNamedQuery("GetCustomers")  
    5.     .scroll(ScrollMode.FORWARD_ONLY);  
    6. while ( customers.next() ) {  
    7.     Customer customer = (Customer) customers.get(0);  
    8.     customer.updateStuff(...);  
    9.     session.update(customer);  
    10. }  
    11.      
    12. tx.commit();  
    13. session.close();  

    DML(Data Manipulation Language数据操作语言)风格操作

    再有就是特殊服务(业务需求)需要我们采用DML(Data Manipulation Language数据操作语言)风格操作,从一张表导入另一张表数据,比方说从学生表(T_Studeng)里面往大三学生表(T_ThreeStudent)里面倒数据.

    1. Session session = sessionFactory.openSession();  
    2. Transaction tx = session.beginTransaction();  
    3.   
    4. String hqlInsert = "insert into ThreeStudent(id, name) select s.id, s.name from Student s where ...";  
    5. int createdEntities = s.createQuery( hqlInsert )  
    6.         .executeUpdate();  
    7. tx.commit();  
    8. session.close();  

    以上就是对批量操作的一点总结,万望对大家能有点帮助

  • 相关阅读:
    Attribute特性 与 Reflection反射技术
    星星评分控件----------WebForm服务器控件开发系列
    CheckBox美化控件----------WinForm控件开发系列
    RadioButton美化控件----------WinForm控件开发系列
    分割线控件----------WinForm控件开发系列
    mysql数据库中自增ID不自增1的解决办法
    [WPF] 操作DataGrid单元格
    [WPF] DataGrid单元格中的TextBox绑定数据源
    WPF中同类型实体间的消息推送
    C#获取屏幕工作区大小
  • 原文地址:https://www.cnblogs.com/DoubleEggs/p/6248508.html
Copyright © 2011-2022 走看看