您如何处理 Spring Data JPA 中 ID 数组的批量删除?

Posted

技术标签:

【中文标题】您如何处理 Spring Data JPA 中 ID 数组的批量删除?【英文标题】:How do you handle with bulk deleting by an array of IDs in Spring Data JPA? 【发布时间】:2016-08-14 06:59:12 【问题描述】:

现在我有一个类用户,我从jsphtml 获得array 的请求数据。

列出这个Integer[] arr=[5,6,9,10,62,52,21]

然后我使用两种方法完成批量删除操作。

@Transactional
@Override
public void deleteUser(Integer id) 

    oneRepository.delete(id);



@Transactional
@Override
public void deleteSomeUser(Integer[] ids) 

    for (Integer id : ids) 

        deleteUser(id);

    


我想知道它是否是一种更有效的方法来完成这个动作。

你可以看到我的日志: 好像不太好!

[94, 95, 91, 92, 93]
Hibernate: 
    delete 
    from
        sshh_user 
    where
        ID=?


Hibernate: 
    delete 
    from
        sshh_user 
    where
        ID=?



Hibernate: 
    delete 
    from
        sshh_user 
    where
        ID=?



Hibernate: 
    delete 
    from
        sshh_user 
    where
        ID=?



Hibernate: 
    delete 
    from
        sshh_user 
    where
        ID=?



Hibernate: 
    select
        count(practice0_.ID) as col_0_0_ 
    from
        sshh_user practice0_

【问题讨论】:

【参考方案1】:

只需将以下内容添加到您的用户存储库界面

void deleteByIdIn(List<Integer> ids);

Spring 将通过方法名派生自动生成适当的查询。

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods

编辑:更多细节

使用 CrudRepositoryJpaRespository 等 Springs Repository 接口带来了基本的数据库操作集,如创建、读取、更新、删除、分页、排序等。

要手动添加一些简单的查询,例如搜索用户名或邮件地址,spring 提供了一种很好的机制,无需注释任何基于字符串的 HQL 查询或类似查询。

Spring 只是分析您的方法名称,搜索关键字。阅读上面提供的关键字的文档链接。

CrudRepository&lt;User&gt; 的示例方法:

Iterable&lt;User&gt; findByNameLike(String search) 解析为 select * from user where name like '&lt;search&gt;'

void deleteByIdIn(List&lt;Integer&gt; ids) 解析为 delete from user where id in ([ids])

更新

这只能在 Spring Boot 版本

自 Spring Boot 2.0 起,它将导致单个删除查询以兑现 JPA 实体生命周期事件,例如 preRemovepostRemove

如果您想真正批量删除,请使用接受的答案。

【讨论】:

您好,请在代码中添加一些解释 - 例如,它的作用等。虽然提供文档链接很有用,但包括该信息对每个人都有好处。 到目前为止,它与 Hibernate 完美配合。另一种(而且更灵活)的方法是使用 QueryDSL (baeldung.com/rest-api-search-language-spring-data-querydsl) 这在 2.0.5.RELEASE 版本中不起作用。 deleteByIdIn 生成与您提供的 ID 数量一样多的删除查询。 请注意,当ids 为空时会引发异常。 试过 deleteByIdIn() 并查看了 Hibernate 调试日志,看起来该方法被翻译成多个删除查询而不是上面提到的单个查询。我最终编写了接受答案中概述的自定义查询。【参考方案2】:

假设你有一个UserRepository 喜欢:

public interface UserRepository extends JpaRepository<User, Integer> 

然后您可以在UserRepository 中添加如下修改查询方法:

/**
 * Delete all user with ids specified in @code ids parameter
 * 
 * @param ids List of user ids
 */
@Modifying
@Query("delete from User u where u.id in ?1")
void deleteUsersWithIds(List<Integer> ids);

最后,您可以更改批量删除服务,如下所示:

@Transactional
@Override
public void deleteSomeUser(Integer[] ids) 
    oneRepository.deleteUsersWithIds(Arrays.asList(ids));

这将生成一个删除查询,如:

Hibernate: delete from users where id in (? , ? , ?)

当您从另一个方法调用public 建议方法时,还要注意Self Invocation 问题。

【讨论】:

更新了关于自我调用的 Spring 文档链接:docs.spring.io/spring/docs/current/spring-framework-reference/… 请注意,这不会自动触发与已删除实体有关系的实体的级联删除,参见。 ***.com/questions/23443188/… 另请注意,子句限制中有sql。例如,在 PostgreSQL 中***.com/questions/1009706/… 请注意,如果ids 为空,则会引发异常。 这对我有用!但是 Spring data JPA 不应该通过方法 repository.deleteAll(entinties) ,repository.deleteAllById(ids) 提供此功能吗?【参考方案3】:

您可以对 deleteAll 项目列表使用不同的方法,而无需调用存储库两次。当 deleteAll 方法调用时,CrudRepository 或 JpaRepository 看起来只是对象 id。

List<User> userList = userIdList.stream().map(id -> 
            User user = new User();
            user.setId(id);
            return user;
        ).collect(Collectors.toList());

userRepository.deleteAll(userList);

【讨论】:

【参考方案4】:

如果您的存储库接口扩展了CrudRepository,您可以简单地使用它的deleteAll(Iterable&lt;? extends T&gt; var1) 方法来删​​除实体集合:

@Repository
public interface UserRepository extends CrudRepository<User, Long> 
    
    void deleteAll(List<User> usersToDelete);


【讨论】:

您应该发布实际代码并将其标记为正确,因为答案是正确的。编辑器顶部有一个按钮,可以从突出显示的文本中创建一个代码块。 不过,他正在使用主键。这个答案假设他正在使用实体,或者将使用 PK 构建一些实体。【参考方案5】:

感谢 rayrayj92 的解决方案。您无需编写任何自定义查询,只需获取对象列表并删除该列表中的所有对象。

@DeleteMapping("/deleteproduct")
public ResponseEntity<?> deleteProduct(@Valid @RequestBody Map<String,Object> userMap)

    List<String> idList=(List<String>) userMap.get("id_list");

    List<Product> productList=(List<Product>) productRepository.findAllById(idList);
    productRepository.deleteAll(productList);
    return ResponseEntity.status(HttpStatus.OK).body("Deleted item : "+productList);


【讨论】:

不建议使用RequestBody和DELETE方法。【参考方案6】:

我已使用此功能删除元素列表 在 JPA 存储库中

void deleteInBatch(List<Integer> list);

【讨论】:

以上是关于您如何处理 Spring Data JPA 中 ID 数组的批量删除?的主要内容,如果未能解决你的问题,请参考以下文章

您如何处理消息队列中乱序的消息?

您如何处理公共 git 存储库中的敏感数据?

您如何处理深度链接插件中的简历场景?

在类似 LMAX 的破坏者模式中,您如何处理缓慢的消费者?

您如何处理模型类中的外键关系

您如何处理排序、分页和过滤的参数?