簡體   English   中英

您可以使用 JPA 和 Hibernate 在一個事務中進行批量刪除嗎?

[英]Can you do bulk delete in one transaction using JPA and Hibernate?

所以,我一直在努力加速從我的數據庫中刪除過程。 我對 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 函數中拉出來,並將它放在對每個對象調用 delete 的 for 循環的末尾。

所以

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();
}

我的另一個批量刪除解決方案是使用休眠 SQLQuery,我只是獲取每個對象的 id 將它們存儲在一個列表中,然后在一個查詢中以這種方式進行批量刪除。 但是,我覺得當我執行該查詢時,由於序列掃描,我的 where id in (?,?,?,?,?) 列表需要更多時間。

我覺得應該有一種簡單的方法可以使用 hibernates session.delete() 進行批量刪除。 任何想法都非常感謝。

使用 Hibernate 和 JPA 執行批量刪除的常用方法與您在上一個解決方案中提出的完全相同 - HQL/JPQL 中的批量刪除查詢

DELETE FROM MyEntity e WHERE e.id IN (:ids)

這應該是迄今為止最有效的一種,因為 Hibernate 不需要加載和實例化實體。

考慮將批量刪除放入它自己的事務方法中,並盡快在其他方法中調用該方法 - 持久性上下文不會隨查詢結果更新,因此您希望防止持久性上下文包含陳舊數據。

使用 JPA 時執行 BUlk Delete 語句的方法有很多。

使用 JPQL 批量刪除

如果要刪除其記錄的表被映射為實體,則可以使用 JPQL [ bulk delete ][1] 語句,如下所示:

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 語句影響的記錄數。 在我們的例子中,它是被刪除的行數。

使用 Criteria API 批量刪除

如果要動態構建 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();

使用 SQL 批量刪除

另一種選擇是使用本機 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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM