给出以下代码,删除批处理中的行。
List<City> list = ...
int i=0;
for(City city:list)
{
if(++i%49==0)
{
entityManager.flush();
}
entityManager.remove(city);
}
JPA 2.1条件API提供CriteriaDelete
来执行批量删除。因此,以下代码执行DELETE FROM city WHERE id IN(...)
查询。
CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaDelete<City> criteriaDelete = criteriaBuilder.createCriteriaDelete(City.class);
Root<City> root = criteriaDelete.from(City.class);
criteriaDelete.where(root.in(list));
entityManager.createQuery(criteriaDelete).executeUpdate();
但这不应该等同于第一种情况。第一种情况相当于什么?它应该批量执行删除。
答案 0 :(得分:1)
等效的是执行查询以删除for循环中的单个实体,如:
for(City city:list)
{
if(++i%49==0)
{
entityManager.flush();
}
CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaDelete<City> criteriaDelete = criteriaBuilder.createCriteriaDelete(City.class);
Root<City> root = criteriaDelete.from(City.class);
criteriaDelete.where(root.equal(city));
entityManager.createQuery(criteriaDelete).executeUpdate();
}
这50个语句中的每一个都可能不会被放入同一批次 - 这取决于您的JPA提供程序是否支持批处理。循环似乎效率较低,因为您最终使用X语句,而不是使用原始批量删除执行的单个DELETE FROM city WHERE id IN(...)
。
答案 1 :(得分:0)
在您的情况下,可能Criteria API 2.1 Bulk Delete效果更好:
CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaDelete<City> criteriaDelete = criteriaBuilder.createCriteriaDelete(City.class);
Root<City> root = criteriaDelete.from(City.class);
criteriaDelete.where(root.in(list));
entityManager.createQuery(criteriaDelete).executeUpdate();
对于批量删除,您根本不需要Criteria API。实际上,您可以保持代码不变:
List<City> list = ...
int i=0;
for(City city:list {
if(++i%49==0) {
entityManager.flush();
}
entityManager.remove(city);
}
您需要做的是enable JDBC batch updates这样:
<property name="hibernate.jdbc.batch_size" value="50"/>
但是,实体级批处理示例需要一些改进。正如我在this article,the best way to do batch processing with JPA and Hibernate中解释的那样,如果您处理数百个实体,那么在批处理期间提交事务也是一个好主意:
int entityCount = 50;
int batchSize = 25;
EntityManager entityManager = null;
EntityTransaction transaction = null;
try {
entityManager = entityManagerFactory()
.createEntityManager();
transaction = entityManager.getTransaction();
transaction.begin();
for ( int i = 0; i < entityCount; ++i ) {
if ( i > 0 && i % batchSize == 0 ) {
entityManager.flush();
entityManager.clear();
transaction.commit();
transaction.begin();
}
Post post = new Post(
String.format( "Post %d", i + 1 )
);
entityManager.persist( post );
}
transaction.commit();
} catch (RuntimeException e) {
if ( transaction != null &&
transaction.isActive()) {
transaction.rollback();
}
throw e;
} finally {
if (entityManager != null) {
entityManager.close();
}
}
这样,您将避免长时间运行的事务,这可能会损害基于2PL和MVCC的关系数据库中的性能。
更多,考虑到你需要更新10K条目并删除3k行,你真的想要回滚所有内容只是因为最后一个SQL语句失败了吗?
atomicity in ACID非常适合OLTP,您只需触摸一小部分数据。对于OLAP或批量处理,最好使用批量更新和删除。