Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/376.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 您可以使用JPA和Hibernate在一个事务中进行批量删除吗?_Java_Hibernate_Jpa_Session_Transactions - Fatal编程技术网

Java 您可以使用JPA和Hibernate在一个事务中进行批量删除吗?

Java 您可以使用JPA和Hibernate在一个事务中进行批量删除吗?,java,hibernate,jpa,session,transactions,Java,Hibernate,Jpa,Session,Transactions,所以,我一直在努力加快数据库的删除过程。我对Hibernate比较陌生,我想知道是否可以在一个事务中执行多个操作 我不太担心事务无法删除,所以回滚所有删除的想法并不困扰我 如果有助于提供表格描述,我也可以这样做。不过,我的想法是,我必须先删除每个for循环内的内容,然后再删除循环外的内容 我的代码 private void deleteTrackItems() { Session session = m_databaseConnection.getSession();

所以,我一直在努力加快数据库的删除过程。我对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);
    }
}
我的另一个批量删除解决方案是使用HibernateSqlQuery,在这里我只获取每个对象的id,将它们存储在一个列表中,然后在一个查询中以这种方式进行批量删除。然而,我觉得当我在(?,,,,,?)列表中查询我的where id时,由于序列扫描,需要花费更多的时间


我觉得应该有一种使用hibernates session.delete()进行批量删除的简单方法。非常感谢您的任何想法。

使用Hibernate和JPA执行批量删除的常用方法正是您在上一个解决方案中提出的方法—HQL/JPQL中的批量删除查询

从MyEntity e中删除,其中e.id位于(:id)

这应该是迄今为止最有效的方法,因为Hibernate不需要加载和实例化实体


考虑将批量删除放在它自己的事务方法中,并在其他方法中尽快调用该方法-持久性上下文不会用查询结果更新,因此,您希望防止持久性上下文包含过时的数据。

在使用JPA时,有许多方法可以执行批量删除语句

使用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();
使用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();
int deleteCount=entityManager.createNativeQuery(“”)
删
哪里
状态=:状态和

更新了方法的次数吗?我严重怀疑查询方法可能比上面的N+1查询策略花费更长的时间。Hibernate仍然会将实体加载到内存中并处理它们的生命周期事件(级联等)。处理级联将违反服务器端删除上的JPA规范:
删除操作仅适用于指定类及其子类的实体。它不会级联到相关实体。
,删除操作还应绕过已加载的实体,但这可能取决于版本或可由H中的设置控制伊比利亚。
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();
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();