如何使用 Spring Data JPA 发出修改查询以通过其 ID 删除一组实体?
How do I issue a modifying query to remove a set of entities by their IDs with Spring Data JPA?
我正在尝试从我的数据库中删除大量记录。每条记录都有一个级联的外键,这样,当通过 JPA 一次删除一条记录时,每次删除大约需要 5 秒。
所以我决定像这样编写一个 JPQL 查询:
@Repository
public interface MyTableRepository extends JpaRepository<MyTable, Long> {
@Query("delete from MyTable where id in :ids")
void deleteAllIds(@Param("ids") Long[] ids);
}
当我 运行 这个,或等效地 void deleteAllIds(@Param("ids") Set<Long> ids);
,我得到以下信息:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [delete from com.lh.clte.domain.content.business.Hotel where id in (:ids_0_, :ids_1_, :ids_2_, :ids_3_, ... for the entire array size)]
org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:293)
org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403)
org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:111)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
com.sun.proxy.$Proxy72.deleteAllId(Unknown Source)
我怎样才能达到我的目标?
您可能想要编写一个单独的服务或 class,您可以在其中编写一些原始 sql。JPA 确实允许您编写本机 sql,但是如果您要做到这一点你应该只写一些原始的 sql 并自己处理它,确保你删除记录和 FK 适用的其他表中的任何关联记录。
要执行修改查询,您需要使用 @Modifying
注释方法,如 reference documentation.
中所述
请注意,发出删除查询不会导致调用受影响实体的任何生命周期回调,因为语句是直接针对数据库执行的。要获得调用的回调,请在给定标识符列表的情况下发出 findAll(…)
并将结果通过管道传输到 deleteAll(…)
.
如果您不管理上述任何层中的事务,请确保您也使用 @Transactional
,以便查询执行 运行 在 JPA 要求的事务中。
我正在尝试从我的数据库中删除大量记录。每条记录都有一个级联的外键,这样,当通过 JPA 一次删除一条记录时,每次删除大约需要 5 秒。
所以我决定像这样编写一个 JPQL 查询:
@Repository
public interface MyTableRepository extends JpaRepository<MyTable, Long> {
@Query("delete from MyTable where id in :ids")
void deleteAllIds(@Param("ids") Long[] ids);
}
当我 运行 这个,或等效地 void deleteAllIds(@Param("ids") Set<Long> ids);
,我得到以下信息:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [delete from com.lh.clte.domain.content.business.Hotel where id in (:ids_0_, :ids_1_, :ids_2_, :ids_3_, ... for the entire array size)]
org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:293)
org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403)
org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:111)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
com.sun.proxy.$Proxy72.deleteAllId(Unknown Source)
我怎样才能达到我的目标?
您可能想要编写一个单独的服务或 class,您可以在其中编写一些原始 sql。JPA 确实允许您编写本机 sql,但是如果您要做到这一点你应该只写一些原始的 sql 并自己处理它,确保你删除记录和 FK 适用的其他表中的任何关联记录。
要执行修改查询,您需要使用 @Modifying
注释方法,如 reference documentation.
请注意,发出删除查询不会导致调用受影响实体的任何生命周期回调,因为语句是直接针对数据库执行的。要获得调用的回调,请在给定标识符列表的情况下发出 findAll(…)
并将结果通过管道传输到 deleteAll(…)
.
如果您不管理上述任何层中的事务,请确保您也使用 @Transactional
,以便查询执行 运行 在 JPA 要求的事务中。