Hibernate 批量处理数据

当要一次事务中需要提交大量数据时,

假设一次性需要向数据库中保存一百万条数据1000000,则常规的保存方式为 :

Session session=null; 
Transaction tx=null; 
try{ 
session=this.getHibernateTemplate().getSessionFactory().openSession(); 
tx=session.beginTransaction(); 
for(int i=0;i<1000000;i++){ 
    s.save(user); 
} 
tx.commit(); 
}finally{ 
   if(session!=null) 
      session.close(); 
} 

上面的保存方式,会出现问题,因为session在调用save方法的时候不会立即将数据保存到数据库,而是先缓存到session范围的一级缓存中,session关闭时,一级缓存也就消失,会将session中的对象清除,一级缓存需要占用内存,而session不能具体控制自己能够保存多少数据,换句话说,只要session不关闭,那么不管你往session里save多少对象session都不管,这就是说session在没关闭前可以拼命缓存对象,当然缓存对象是要消耗内存的,这样一来,当数据量很大的时候内存就会被消耗完,产生内存溢出,上面的代码就会出现这样的问题,当然也许你机子内存很大很大,运行上面代码没有内存溢出,那么你可以将保存数据的条数增加到千万或者十亿,相信你机子这时候会内存溢出。

问题出现了,那么怎样来解决

第一种:通过Session来进行批量操作

 配置hibernate.jdbc.batch_size参数的原因就是尽量少读数据库,hibernate.jdbc.batch_size参数值越大,读数据库的次数越少,速度越快。从上面的配置可以看出,Hibernate是等到程序积累到了50个SQL之后再批量提交。

  设置hibernate.jdbc.batch_size参数,可参考如下配置。

<hibernate-configuration>
 <session-factory>……
    <property name=“ hibernate.jdbc.batch_size”>50</property>……
  <session-factory> 
<hibernate-configuration>
Session session=null; 
Transaction tx=null; 
try{ 
session=this.getHibernateTemplate().getSessionFactory().openSession(); 
tx=session.beginTransaction(); 
for(int i=0;i<1000000;i++){ 
    s.save(user); 
    if(i%50==0){ 
       s.flush(); 
       s.clear(); 
} 
} 
tx.commit(); 
}finally{ 
   if(session!=null) 
      session.close(); 
} 

相信你发现了这段代码与前面那段代码的不同之处,是多了 

   if(i%50==0){ 

       s.flush(); 
       s.clear(); 

    }

那么接下来就说说加这段代码的作用if(i%50==0)判断每次循环后session是否达到50个对象,这个设置可根据需要自己设定,设置的数字越小则与数据库的交互次数就越多,设置得越大,与数据库的交互次数越少,但是消耗的内存就更多,如果太大同样会内存溢出,因此设置一个合理的大小很重要,当session中达到了设置的对象个数后,调用s.flush();方法,该方法的作用是让session中的对象与数据库同步,也就是说让session数据与数据库中一致,会调用操作数据库的方法,简单地说会执行sql语句,在上例中就是会将50个对象批量插入到数据库来达到一致,数据库插入之后调用s.clear(); 方法,这个方法会清除掉session中的缓存对象,在上面来说就是会清除掉50个对象,将内存释放,因此上面的代码是每到50个对象的时候将数据插入到数据库并将session中的缓存对象清除,所以不会有内存溢出 

第二种: 用StatelesssSession接口

它不和一级缓存,二级缓存交互,也不触发任何时间,监听器,拦截器,通过该接口会立刻发送到数据库 

StatelessSession session = sessionFactory.openStatelessSession(); 
Transaction tx = session.beginTransaction();   
ScrollableResults customers = session.getNamedQuery("GetCustomers") 
    .scroll(ScrollMode.FORWARD_ONLY); 
while ( customers.next() ) { 
    Customer customer = (Customer) customers.get(0); 
    customer.updateStuff(...); 
    session.update(customer); 
} 
tx.commit(); 
session.close(); 
注意在上面的例子中,查询返回的Customer实例立即被脱管(detach)。它们与任何持久化上下文都没有关系。 

StatelessSession 接口定义的insert(), update() 和 delete()操作是直接的数据库行级别操作,其结果是立刻执行一条INSERT, UPDATE 或 DELETE 语句。因此,它们的语义和Session 接口定义的save(), saveOrUpdate() 和delete() 操作有很大的不同。

第三种: 用HQL来进行批量处理

对象的状态存在于内存,HQL操作实际上是在数据库中完成的,因此直接更新或者删除 (使用 SQL 语句 UPDATE 和 DELETE) 数据库中的数据将不会影响内存中的对象状态和对象数据。

使用Query.executeUpdate()方法执行一个HQL UPDATE语句: 

Session session = sessionFactory.openSession(); 
        Transaction tx = session.beginTransaction(); 
        String hqlUpdate = "update Customer set name = :newName where name =“ldName"; 
        int updatedEntities = s.createQuery( hqlUpdate ) 
                            .setString( "newName", newName ) 
                            .setString( "oldName", oldName ) 
                            .executeUpdate(); 
        tx.commit(); 
        session.close(); 
执行一个HQL DELETE,同样使用 Query.executeUpdate() 方法 (此方法是为 那些熟悉JDBC PreparedStatement.executeUpdate() 的人们而设定的) 
Session session = sessionFactory.openSession(); 
        Transaction tx = session.beginTransaction(); 
        String hqlDelete = "delete Customer where name =”ldName"; 
        int deletedEntities = s.createQuery( hqlDelete ) 
                            .setString( "oldName", oldName ) 
                            .executeUpdate(); 
        tx.commit(); 
        session.close(); 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值