在您的情况下,可能是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);
}
您需要做的是启用 JDBC 批量更新,如下所示:
<property name="hibernate.jdbc.batch_size" value="50"/>
但是,实体级批处理示例需要一些改进。正如我在本文中解释的那样,如果您处理数百个实体,使用 JPA 和 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 语句失败而回滚所有内容?
ACID中的原子性非常适合只接触一小部分数据的 OLTP。对于 OLAP 或批量处理,最好改为使用批量更新和删除。