您如何处理 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 【问题描述】:现在我有一个类用户,我从jsp
或html
获得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
编辑:更多细节
使用 CrudRepository
、JpaRespository
等 Springs Repository 接口带来了基本的数据库操作集,如创建、读取、更新、删除、分页、排序等。
要手动添加一些简单的查询,例如搜索用户名或邮件地址,spring 提供了一种很好的机制,无需注释任何基于字符串的 HQL 查询或类似查询。
Spring 只是分析您的方法名称,搜索关键字。阅读上面提供的关键字的文档链接。
CrudRepository<User>
的示例方法:
Iterable<User> findByNameLike(String search)
解析为 select * from user where name like '<search>'
void deleteByIdIn(List<Integer> ids)
解析为 delete from user where id in ([ids])
更新:
这只能在 Spring Boot 版本
自 Spring Boot 2.0 起,它将导致单个删除查询以兑现 JPA 实体生命周期事件,例如 preRemove
和 postRemove
。
如果您想真正批量删除,请使用接受的答案。
【讨论】:
您好,请在代码中添加一些解释 - 例如,它的作用等。虽然提供文档链接很有用,但包括该信息对每个人都有好处。 到目前为止,它与 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<? extends T> 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 数组的批量删除?的主要内容,如果未能解决你的问题,请参考以下文章