因此,我一直在试图加速数据库中的删除过程。我对hibernate相对较新,并且想知道是否可以在一个事务中执行多个操作。
我不担心交易无法删除,因此回滚所有删除的想法并不会让我感到烦恼。如果它有助于提供表格描述,我也可以这样做。但这个想法是我必须删除每个for循环中的内容才能删除它之外的内容。
我的代码
private void deleteTrackItems() {
Session session = m_databaseConnection.getSession();
Transaction tx = null;
try {
final List<TrackItem> trackItems = loadAllTrackItemByTrackID(
track.getId(), session);
// Deletes all Track Items for the given track
List<Long> trackItemIds = new ArrayList();
for (TrackItem trackItem : trackItems) {
trackItemIds.add(trackItem.getId());
// this is test code 189 through 214
Set<TrackPoint> trackPoints = trackItem.getTrackPoints();
for (TrackPoint trackPoint : trackPoints) {
// load track
final List<TrackPointDetail> trackPointDetails = loadAllTrackPointDetailByTrackID(
trackPoint.getId(), session);
for (TrackPointDetail trackPointDetail : trackPointDetails) {
// delete track point details
deleteObject(trackPointDetail, session);
}
// delete track point
deleteObject(trackPoint, session);
}
// get the track informations
final Set<TrackInformation> trackInformations = trackItem
.getTrackInformations();
// for each track information
for (TrackInformation trackInformation : trackInformations) {
deleteTrackInformation(trackInformation, session);
}
deleteObject(trackItem, session);
}
}
catch (Exception ex) {
System.out.println(ex);
tx.rollback();
}
finally {
if (session != null) {
session.close();
}
}
}
/**
* @param p_objectToDelete The object to delete
* @param p_session the hibernate session
* @return Returns the {@link Runnable}
*/
protected void deleteObject(Object p_objectToDelete, final Session p_session) {
// get the transaction
final Transaction transaction = p_session.getTransaction();
try {
LOGGER.info("Deleting object: " + p_objectToDelete.getClass());
transaction.begin();
p_session.delete(p_objectToDelete);
transaction.commit();
LOGGER.info("Deleted object: " + p_objectToDelete.getClass());
}
catch (Exception exception) {
transaction.rollback();
LOGGER.error(exception);
}
}
因为这些操作中的每一个当前在每次删除后执行提交,所以我想知道是否可以在更多的批量操作中执行此操作。
我正在考虑做的事情就是将我的提交从我的deleteObject函数拉出来并将其放在for循环的末尾,该循环在每个对象上调用delete。
所以
final Transaction tx = session.getTransaction();
transaction.begin();
try{
for(Object object : objects){
session.delete(object);
}
tx.commit();
}catch(Exception ex){
System.out.println(ex);
tx.rollback();
}
批量删除的另一个解决方案是使用一个hibernate SQLQuery,我只是获取每个对象的id,将它们存储在一个列表中,并在一个查询中以这种方式进行批量删除。但是我觉得当我进行查询时,由于序列扫描,我在哪里(?,?,?,?,?)列表需要更多时间。
我觉得应该有一个简单的方法来使用hibernates session.delete()进行批量删除。非常感谢任何想法。
答案 0 :(得分:4)
使用Hibernate和JPA执行批量删除的常用方法与您在上一个解决方案中提出的完全相同 - HQL / JPQL中的批量删除查询
DELETE FROM MyEntity e WHERE e.id IN (:ids)
这应该是最有效的,因为Hibernate不需要加载和实例化实体。
考虑将批量删除放入其自己的事务方法中,并在您的其他方法中尽快调用该方法 - 持久性上下文不会随查询结果一起更新,因此您希望阻止持久性上下文包含陈旧的数据。
答案 1 :(得分:0)
使用JPA时,有很多方法可以执行BUlk Delete语句。
如果要将要删除其记录的表映射为一个实体,则可以使用JPQL批量删除语句,如下所示:
int deleteCount = entityManager.createQuery("""
delete from Post
where
status = :status and
updatedOn <= :validityThreshold
""")
.setParameter("status", PostStatus.SPAM)
.setParameter(
"validityThreshold",
Timestamp.valueOf(
LocalDateTime.now().minusDays(7)
)
)
.executeUpdate();
executeUpdate
方法返回一个int
值,该值表示受DML语句影响的记录数。在我们的例子中,这就是被删除的行数。
有关使用JPA批量更新和删除查询的更多详细信息,请查看this article。
如果要动态构建Bulk Delete语句,则可以使用JPA CriteriaDelete
查询:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaDelete<T> delete = builder.createCriteriaDelete(postModerateClass);
Root<T> root = delete.from(postModerateClass);
int daysValidityThreshold = (Post.class.isAssignableFrom(postModerateClass)) ? 7 : 3;
delete.where(
builder.and(
builder.equal(
root.get("status"),
PostStatus.SPAM
),
builder.lessThanOrEqualTo(
root.get("updatedOn"),
Timestamp.valueOf(
LocalDateTime
.now()
.minusDays(daysValidityThreshold)
)
)
)
);
int deleteCount = entityManager.createQuery(delete).executeUpdate();
有关使用Criteria API批量更新和删除查询的更多详细信息,请查看this article。
另一种替代方法是使用本机SQL执行批量删除语句:
int deleteCount = entityManager.createNativeQuery("""
delete from post
where
status = :status and
updated_on <= :validityThreshold
""")
.setParameter("status", PostStatus.SPAM.ordinal())
.setParameter(
"validityThreshold",
Timestamp.valueOf(
LocalDateTime.now().minusDays(7)
)
)
.executeUpdate();