【问题标题】:How do you handle with bulk deleting by an array of IDs in Spring Data JPA?您如何处理 Spring Data JPA 中 ID 数组的批量删除?
【发布时间】: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_

【问题讨论】:

    标签: hibernate spring-mvc spring-data spring-data-jpa


    【解决方案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 问题。

    【讨论】:

    【解决方案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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-27
        • 1970-01-01
        • 1970-01-01
        • 2018-01-23
        • 2018-10-14
        • 1970-01-01
        • 2013-08-26
        • 1970-01-01
        相关资源
        最近更新 更多