• Hibernate的批量处理数据


      通常在一个Session对象中存放的持久化对象是有限的。等到Session处理事物完毕,还要关闭Session对象,从而及时释放Session的缓存占用的内存。

    当一个事物中要处理大批量的数据时,一般来说是应该尽量避免在应用层进行批量的操作,而应该在数据库层直接进行批量的操作。例如:直接在数据库中执行批量更新或删除的SQL语句,如果批量操作的逻辑比较复杂,则可以通过直接在数据库中运行存储过程来完成批量操作, 当然,在应用层也可以进行批量操作,主要有以下方式:

      1)。通过Session来进行批量操作。

      2)。通过StatelessSession来进行批量操作。

      3)。通过HQL来进行批量操作。

      4)。直接通过JDBC API来进行批量操作。

    通过Session来进行批量操作:

      Session的save()及update()方法都会把处理的对象存放在自己的缓存中,处理通过一个Session对象来处理大量持久化对象,应该及时的从缓存中清空已经处理完毕并且不在访问的对象,具体的做法是在处理完一个对象或者小批量后,立刻调用flush()方法清理缓存,然后调用clear()方法清空缓存。

      通过Session来进行批量处理会受到以下约束:

        1)。需要在hibernate的配置文件中设置jdbc单次批量处理的数目,合理的取值通常为10~50

          hibernate.jdbc.batch_size
        2)。如果对象采用“identity”标示符生成器,则无法在jdbc层进行批量操作。
        3)。进行操作是建议关闭hibernate的第二级缓存。
    批量插入:
    Session session = Sessionfactory.openSession();
    Transaction tx = session.beginTransaction();
    for(int = 0; i <100000;i++){
    Customer customer = new Customer(....);
    session.save(customer);
    if( i % 20 == 0){//单次批量操作数量为20
    session.flush();//清理缓存,执行批量插入20条记录的SQL insert语句
    session.clear();//清空缓存中的Customer对象
    }
    }

    tx.commit();
    session.close();


    批量更新:
    Session  session  = new Sessionfactory.openSession();
    Transaction tx = session.beginTransction();
    ScrollableReaults customers = session.createQuery("from Customer");
    int count = 0;
    while(customer.next()){
    Custmoer customer = new Custmoer(............);
    customer.setAge(customer.getAge()+1);//更新Custmoer对象age的属性
    if(++count % 20 == 0){
    session.flush();//清理缓存
    session.clear();//清空缓存中的Customer对象
    }
    }

    tx.commit();
    session.close();


    通过StatelessSession来进行批量操作
      Session 具有一个用于保存内存中对象与数据库中相应数据保持同步的缓存,位于缓存中的对象为持久化对象,但在进行批量操作的时候,把大量对象放入缓存中会消耗大量的内存空间,作为一种
    替代方案,可以采用无状态的StatelessSession来进行批量的操作。
    StatelessSession session  = sessionFactory.openStatelessSession();
    Transaction tx = session.beginTransaction();
    ScrollableResults customers = session.getNamedQuery("GetCustomers")
    .scroll(ScrollMode.FORWQRD_ONLY);
    while(customers.next()){
    Customer customer = (Customer) customer.get(0);
    customer.setAge(customer.getAge()+1);//在内存中更新Customer对象的age属性
    session.update(customer);//立即执行update语句,更新数据库中相应数据
    }
    tx.commit();
    session.close();


    从形式上看StatelessSession与Session的用法有点相似,有以下区别:
      1)。StatelessSession没有缓存,通过StatelessSession来加载,保存或更新后的对象都处于游离状态。
      2)。StatelessSession不会雨hibernate的第二级缓存交互。
      3)。当调用StatelessSession的save()、update()或delete()方法时,这些方法会立即执行相应的SQL语句,而不会仅计划执行一条SQL语句。
      4)。StatelessSession不会对所加载的对象自动进行脏检查,所以在以上程序中修改了内存中的Customer对象的属性后,还需要通过StatelessSession的update()更新数据库中的相应数据。
      5)。StatelessSession不会对关联的对象进行任何级联操作。
      6)。StatelessSession所做的操作可以被Interceptor拦截器捕获到,但会被hibernate的时间处理所忽略!
      7)。通过一个StatelessSession对象两次加载OID为1的Customer对象时,会得到两个不同内存地址的Customer。
    通过HQL来进行批量操作:
    Session session = SessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
    int updateEntieies = session.createQuery(hqlUpdate);
    .setString("newName","Mike")
    .setString("oldName","Tom")
    .executeUpdate();
    tx.commit();
    session.close();


    通过JDBC API来进行批量操作:
     Transaction tx = session.beginTransaction();
    java.sql.Connection con = session.connection();
    PreparedStatement stmt = con.prepareStatement("update CUSTOMER set AGE = AGE + 1 where = AGE > 0");
    stmt.executeUpdate();
    tx.commit();
    *在hibernate3中尽管Session的connection()方法还存在,但是已经被废弃,不提倡使用了,不过Hibernate3提供了替代的方案:org.hibernate.jdbc.Work接口表示直接通过JDBC API来
    访问数据库的操作,Work接口的execute()方法用于执行直接通过JDBC API来访问数据库的操作。
    public interface Work{
    //直接通过JDBC API 来访问数据库
    public void execute(Connection connection ) throws SQLExectpion;
    }
     Transaction tx = session.beginTransaction();
    Work work = new Work(){
    public void execute(Connection connection ) throws SQLException{
    PreparedStatement stmt = connection.prepareStatement("update CUSTOMER set AGE = AGE + 1 where AGE > 0");
    stmt.executeUpdate();
    }
    }
    //执行Work
    session.doWork(work);
    tx.commit();





                                      

  • 相关阅读:
    [机器人仿真软件(一)]V-REP与MATLAB进行通讯的方法
    TCP接收非法数据0xFFF4FFFD06的问题
    std::numeric_limits::epsilon
    linux 设置默认网关
    更换pip源
    实时屏幕传输
    安装node
    window 添加服务
    数据集格式
    jupyter 设置密码
  • 原文地址:https://www.cnblogs.com/dengpengbo/p/2224983.html
Copyright © 2020-2023  润新知