简体   繁体   中英

How do I issue a modifying query to remove a set of entities by their IDs with Spring Data JPA?

I am trying to remove a very large number of records from my database. Each record has a cascade of Foreign Key such that, when deleting a record at a time via JPA, each removal requires around 5s.

So I decided to write a JPQL query like this:

@Repository
public interface MyTableRepository extends JpaRepository<MyTable, Long> {
    @Query("delete from MyTable where id in :ids")
    void deleteAllIds(@Param("ids") Long[] ids);
}

When I run this, or equivalently, void deleteAllIds(@Param("ids") Set<Long> ids); , I get the following:

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)

How can I get to my goal?

To execute a modifying query you need to annotate the method with @Modifying as described in the reference documentation .

Note, that issuing a delete query will not cause any lifecycle callbacks of the affected entities to be called as the statement is executed against the database directly. To get the callbacks called issue a findAll(…) given the list of identifiers ad pipe the results into deleteAll(…) .

If you don't manage transactions in any of the above layers, make sure you also use @Transactional so that the query execution is running in a transaction as required by JPA.

您可能想要编写一个单独的服务或类,您可以编写一些原始sql。JPA允许您编写本机sql,但是如果您打算用它去那么远,您应该只编写一些原始sql并处理它您自己,确保删除FK适用的其他表中的记录和任何相关记录。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM