我正在使用休眠更新数据库中的 20K 产品。
到目前为止,我正在提取 20K 产品,遍历它们并修改一些属性,然后更新数据库。
所以:
load products
foreach products
session begintransaction
productDao.MakePersistant(p);
session commit();
到目前为止,与您的标准 jdbc 相比,事情进展得很慢,我能做些什么来加快速度?
我确定我在这里做错了什么。
我正在使用休眠更新数据库中的 20K 产品。
到目前为止,我正在提取 20K 产品,遍历它们并修改一些属性,然后更新数据库。
所以:
load products
foreach products
session begintransaction
productDao.MakePersistant(p);
session commit();
到目前为止,与您的标准 jdbc 相比,事情进展得很慢,我能做些什么来加快速度?
我确定我在这里做错了什么。
在文档中查看这种处理的正确位置是整个第 13 章。批处理。
在这里,您当前的方法有几个明显的错误:
您应该启用 JDBC 批处理并将其设置为合理的数字(10-50):
hibernate.jdbc.batch_size 20
您应该flush()
然后clear()
定期进行会话(每 n 条记录,其中 n 等于hibernate.jdbc.batch_size
参数),否则它将继续增长并可能OutOfMemoryException
在某个时候爆炸(带有 )。
下面,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();
您也可以考虑使用StatelessSession。
另一种选择是使用DML 样式的操作(在 HQL 中!):UPDATE FROM? EntityName (WHERE where_conditions)?
. 这是 HQL 更新示例:
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();
同样,请参阅文档以获取详细信息(尤其是如何使用关键字处理version
ortimestamp
属性值)。VERSIONED
如果这是伪代码,我建议将事务移出循环,或者如果在单个事务中包含所有 20K 产品太多,则至少有一个双循环:
load products
foreach (batch)
{
try
{
session beginTransaction()
foreach (product in batch)
{
product.saveOrUpdate()
}
session commit()
}
catch (Exception e)
{
e.printStackTrace()
session.rollback()
}
}
另外,我建议您批量更新,而不是将每个更新单独发送到数据库。那样的话网络流量太大了。将每个块捆绑成一个批次并一次发送它们。
我同意上面关于查看批处理章节的答案。
我还想补充一点,您应该确保只加载对产品进行更改所需的内容。
我的意思是,如果产品急切地加载大量对该事务不重要的其他对象,您应该考虑不加载连接的对象 - 它会加快产品的加载速度,并且根据它们的持久性策略,也可能在使产品再次持久化时节省您的时间。
进行批量更新的最快方法是将其转换为单个 SQL 语句并在会话上作为原始 sql 执行。就像是
update TABLE set (x=y) where w=z;
如果失败,您可以尝试减少事务并批量更新:
start session
start transaction
products = session.getNamedQuery("GetProducs")
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
count=0;
foreach product
update product
if ( ++count % 20 == 0 ) {
session.flush();
session.clear();
}
}
commit transaction
close session
有关更多信息,请查看Hibernate 社区文档