单向一对多映射下如何删除BorrowedBooks关联表的行
问题分析与解决方案
当前代码执行后仅将BorrowedBooks表对应行的user_id设为null,而非删除实体,核心原因有两点:
- 单向一对多关联未配置级联删除,移除集合元素仅会解除关联关系,不会删除数据库中的实体
- 循环删除的逻辑存在索引移位问题,可能导致漏删目标实体
方案1:配置级联删除+修正遍历逻辑
步骤1:修改User实体的关联注解
在@OneToMany中添加CascadeType.REMOVE(或用CascadeType.ALL,但需注意级联操作的范围),让JPA在移除集合元素时自动删除对应的BorrowedBooks实体:
@Entity @Table(name="user") public class User { // ...其他字段 @OneToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE,CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, fetch=FetchType.LAZY) @JoinColumn(name="user_id") private List<BorrowedBooks> borrowedBooks; // ...其他方法 }
步骤2:修正控制器的删除逻辑
使用迭代器遍历集合(避免索引移位导致的漏删),移除目标实体:
@GetMapping("/returnBooks") public String returnBooks(@RequestParam List<Integer> bookId) { int userId = CurrentUser.getCurrentUserId(); User theUser = userService.findById(userId); List<BorrowedBooks> borrowedBooks = theUser.getBorrowedBooks(); // 迭代器遍历,安全删除元素 Iterator<BorrowedBooks> iterator = borrowedBooks.iterator(); while (iterator.hasNext()) { BorrowedBooks book = iterator.next(); if (bookId.contains(book.getBookId())) { iterator.remove(); // 移除集合元素,触发级联删除 } } userService.save(theUser); return "success"; }
方案2:手动删除实体(不依赖级联)
如果不想启用级联删除(避免误删其他场景下的实体),可以单独注入BorrowedBooks的Service/Repository,手动删除目标实体:
@Autowired private BorrowedBooksService borrowedBooksService; @GetMapping("/returnBooks") public String returnBooks(@RequestParam List<Integer> bookId) { int userId = CurrentUser.getCurrentUserId(); User theUser = userService.findById(userId); List<BorrowedBooks> borrowedBooks = theUser.getBorrowedBooks(); // 筛选出需要删除的实体 List<BorrowedBooks> toDelete = borrowedBooks.stream() .filter(book -> bookId.contains(book.getBookId())) .collect(Collectors.toList()); // 先删除数据库中的实体 toDelete.forEach(borrowedBooksService::delete); // 从用户的关联集合中移除 borrowedBooks.removeAll(toDelete); userService.save(theUser); return "success"; }
内容的提问来源于stack exchange,提问作者Mathew Pius
相关产品推荐
相关产品推荐

