JPA删除Post方法执行但未删除数据库对象问题求助
我有一个User类,和Comment、Post是一对多关系:每个用户可拥有多个帖子和评论,每个帖子也可拥有多个评论。现在执行Post删除方法时,方法正常运行但数据库中对象未被删除。奇怪的是,若不从请求头获取User而是传入new User(),删除就能正常工作,求解决。
User实体类
@Entity @Getter @Setter public class User { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) private Long userId; private String email; @OneToMany (mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) private List<Post> posts; @OneToMany (mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) private List<Comment> comments; }
Post实体类
@Entity @Getter @Setter public class Post { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) private Long postId; @OneToMany (mappedBy = "post", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) private List<Comment> comments; @ManyToOne(fetch = FetchType.LAZY) @OnDelete(action = OnDeleteAction.CASCADE) @JsonIgnore @JoinColumn (name = "user_id") private User user; }
Post控制器类
@RestController @RequestMapping("/api/posts") @AllArgsConstructor public class PostController { private final PostService postService; private final UserService userService; @DeleteMapping("/{postId}") public ResponseEntity<?> deletePostById (@PathVariable Long postId, @RequestHeader("Authorization") String authorization) { Post post = postService.getPostById(postId).getData(); String email = JwtUtils.getEmailFromHeader(authorization); User user= userService.getUserByEmail(email); Result result = postService.deletePost(post, user); return new ResponseEntity<>(result, HttpStatus.OK); } }
Post服务类中的删除方法
public Result deletePost(Post post, User user) { try { if (post == null) { return new Result(false, POST_NOT_FOUND); } else if (user.getUserId().equals(post.getUser().getUserId())) { postRepository.delete(post); return new Result(true, POST_DELETED); } else { return new Result(false, PERMISSION_DENIED); } } catch (Exception e) { return new Result(false, e.getMessage()); } }
问题原因及解决方案
核心问题:实体持久化状态冲突
从请求头获取的User是Spring Data JPA从数据库加载的持久化状态实例(受EntityManager管理),而new User()是未被管理的瞬时状态。当你执行post.getUser().getUserId()时,因为Post的user配置了懒加载,这里会触发EntityManager加载关联的User实例,此时对比两个User的ID后,执行postRepository.delete(post)时,EntityManager的状态同步出现异常,导致删除操作未同步到数据库。
具体修复方案
给删除方法加上事务注解
Spring Data JPA的delete操作必须在事务上下文才能生效,给deletePost方法加上@Transactional注解:@Transactional public Result deletePost(Post post, User user) { // 原有逻辑不变 }优化权限校验逻辑,避免不必要的懒加载
不要通过post.getUser().getUserId()触发懒加载,而是在查询Post时就关联加载User,或者直接通过Post的外键字段校验:方法一:修改
getPostById方法,用Fetch Join加载User
在PostRepository中添加查询方法:@Query("SELECT p FROM Post p JOIN FETCH p.user WHERE p.postId = :postId") Post findByIdWithUser(@Param("postId") Long postId);然后在服务类中用这个方法获取Post,这样Post的User已经被加载,不会触发懒加载,实体状态一致。
方法二:直接通过ID组合删除,跳过实体加载
在PostRepository中添加批量删除方法:@Modifying @Transactional @Query("DELETE FROM Post p WHERE p.postId = :postId AND p.user.userId = :userId") int deleteByPostIdAndUserId(@Param("postId") Long postId, @Param("userId") Long userId);然后修改服务类的删除逻辑:
public Result deletePost(Long postId, User user) { try { int deletedCount = postRepository.deleteByPostIdAndUserId(postId, user.getUserId()); if (deletedCount == 0) { return new Result(false, "帖子不存在或无权限删除"); } return new Result(true, POST_DELETED); } catch (Exception e) { return new Result(false, e.getMessage()); } }这种方式不需要加载整个Post和User实体,性能更高,也避免了实体状态问题。
清理重复的级联配置
去掉Post类中的@OnDelete(action = OnDeleteAction.CASCADE),因为User的@OneToMany已经配置了cascade = CascadeType.ALL和orphanRemoval = true,重复配置可能导致冲突。
内容的提问来源于stack exchange,提问作者Adem Galitekin

