如何解决为什么我需要@Transactional来保存OneToOne映射实体
我有一个简单的简单演示应用程序,其中包含spring-boot,spring-data-jpa和h2-DB。
我已经建立了两个通过OneToOne
关系映射的实体。
Post.java
@Entity
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@OneToOne(mappedBy = "post",cascade = CascadeType.ALL,fetch = FetchType.LAZY)
private PostDetail postDetail;
}
PostDetail.java
@Entity
public class PostDetail {
@Id
@GeneratedValue
private Long id;
private String message;
@OneToOne(fetch = FetchType.LAZY)
@MapsId
@JoinColumn(name = "id")
private Post post;
}
我尝试创建并保存一个新的Post
。然后,我尝试创建一个新的PostDetail
,将先前生成的Post
设置为它并保存。在一个控制器示例中,我没有@Transactional
批注;在第二个示例中,我使用@Transactional
@RestController
public class TestController {
@Autowired
PostRepository postRepository;
@Autowired
PostDetailRepository postDetailRepository;
@GetMapping("/test1")
public String test1() {
Post post = new Post();
post.setId(2L);
post.setTitle("Post 1");
postRepository.save(post);
PostDetail detail = new PostDetail();
detail.setMessage("Detail 1");
detail.setPost(post);
postDetailRepository.save(detail);
return "";
}
@Transactional
@GetMapping("/test2")
public String test2() {
Post post = new Post();
post.setId(2L);
post.setTitle("Post 1");
postRepository.save(post);
PostDetail detail = new PostDetail();
detail.setMessage("Detail 1");
detail.setPost(post);
postDetailRepository.save(detail);
return "";
}
}
为什么在第一个示例中出现org.hibernate.PersistentObjectException: detached entity passed to persist: com.example.demo.jpa.model.Post
异常而在另一个示例中没有异常?
谁能解释为什么会这样?
解决方法
您不应该分别保存这两个实体-您应该在post对象内部设置PostDetail,而仅保存Post对象。 Hibernate将负责保存汇总的PostDetail。
这就是为什么您得到PersistentObjectException
的原因,可以通过将其保存在同一笔交易中来解决该问题。
您使用双向 @OneToOne
关联。作为休眠文档states:
每当建立双向关联时,应用程序开发人员就必须确保双方始终保持同步。
因此,您应该以这种方式重写测试方法:
@GetMapping("/test1")
public String test1() {
Post post = new Post();
post.setId(2L);
post.setTitle("Post 1");
PostDetail detail = new PostDetail();
detail.setMessage("Detail 1");
// synchronization of both sides of @OneToOne association
detail.setPost(post);
post.setDetail(detail);
// thanks to CascadeType.ALL on Post.postDetail
// postDetail will be saved too
postRepository.save(post);
return "";
}
,
we do not always need a bidirectional mapping when we are mapping two entities
you can simple have a unidirection most of the time
Post post = new Post();
post.setId(2L);
post.setTitle("Post 1");
PostDetail detail = new PostDetail();
detail.setMessage("Detail 1");
detail.setPost(post);
postRepository.save(post);
由于您拥有cascade.all,所以休眠首先保存Post,然后保存PostDetail,现在根据Transaction行为的规则,它是完全完成还是未完成,因此我们无法保存Post但PostDetail却没有,因此避免这种歧义,在方法级别或根据您的要求可能是类级别使用@Transaction批注很重要
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。