使用Hibernate加载20K产品,修改实体并更新到db

Bla*_*man 7 java orm hibernate data-processing

我正在使用hibernate来更新我的数据库中的20K产品.

截至目前,我正在提取20K产品,循环遍历它们并修改一些属性,然后更新数据库.

所以:

load products

foreach products
   session begintransaction
   productDao.MakePersistant(p);
   session commit();
Run Code Online (Sandbox Code Playgroud)

截至目前,与标准的jdbc相比,事情相当缓慢,我该怎么做才能加快速度?

我相信我在这里做错了什么.

Pas*_*ent 10

在这种处理的文档中查看的正确位置是整个第13章.批处理.

在这里,您当前的方法有几个明显的错误:

  • 您不应该为每次更新启动/提交事务.
  • 你应该启用JDBC批处理并将其设置为合理的数字(10-50):

    hibernate.jdbc.batch_size 20
    
    Run Code Online (Sandbox Code Playgroud)
  • 你应该flush()然后clear()定期会话(每n个记录,其中n等于hibernate.jdbc.batch_size参数),或者它会继续增长,并且可能会OutOfMemoryException在某个时刻爆炸(带有a ).

下面是13.2节中给出的例子.批量更新说明了这一点

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

ScrollableResults customers = session.getNamedQuery("GetCustomers")
    .setCacheMode(CacheMode.IGNORE)
    .scroll(ScrollMode.FORWARD_ONLY);
int count=0;
while ( customers.next() ) {
    Customer customer = (Customer) customers.get(0);
    customer.updateStuff(...);
    if ( ++count % 20 == 0 ) {
        //flush a batch of updates and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();
Run Code Online (Sandbox Code Playgroud)

您也可以考虑使用StatelessSession.

另一种选择是使用DML风格的操作(在HQL!) UPDATE FROM? EntityName (WHERE where_conditions)?.这是HQL UPDATE示例:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
int updatedEntities = s.createQuery( hqlUpdate )
        .setString( "newName", newName )
        .setString( "oldName", oldName )
        .executeUpdate();
tx.commit();
session.close();
Run Code Online (Sandbox Code Playgroud)

再次,请参阅文档以获取详细信息(特别是如何使用关键字处理versiontimestamp属性值VERSIONED).


duf*_*ymo 5

如果这是伪代码,我建议在循环外移动事务,或者如果单个事务中的所有20K产品都太多,则至少要有一个双循环:

load products
foreach (batch)
{
   try
   {
      session beginTransaction()
      foreach (product in batch)
      {
          product.saveOrUpdate()
      }
      session commit()
   }
   catch (Exception e)
   {
       e.printStackTrace()
       session.rollback()
   }
}
Run Code Online (Sandbox Code Playgroud)

另外,我建议您批量更新UPDATE,而不是将每个UPDATE单独发送到数据库.这样的网络流量太多了.将每个块捆绑成一个批次并立即发送它们.