Spring Boot中@OneToMany与@ManyToOne几个需要注意的问题

来源:互联网 发布:做淘宝联盟怎么样 编辑:程序博客网 时间:2024/05/16 13:39

@OneToMany如果不加@JoinColumn,系统会自动在主从表中增加一个中间表。

主表:

@Entity(name = "Post")public class Post {      @Id    @GeneratedValue    private Long id;      private String title;      @OneToMany(        cascade = CascadeType.ALL,         orphanRemoval = true    )    private List<PostComment> comments = new ArrayList<>(); }

从表:

@Entity(name = "PostComment")public class PostComment {      @Id    @GeneratedValue    private Long id;      private String review; }
如果使用下面代码添加1条主表记录以及3条从表记录:

Post post = new Post("First post");  post.getComments().add(    new PostComment("My first review"));post.getComments().add(    new PostComment("My second review"));post.getComments().add(    new PostComment("My third review"));  entityManager.persist(post);

实际上系统会执行7条SQL语句
insert into post (title, id) values ('First post', 1)  insert into post_comment (review, id) values ('My first review', 2)   insert into post_comment (review, id) values ('My second review', 3)  insert into post_comment (review, id) values ('My third review', 4)  insert into post_post_comment (Post_id, comments_id) values (1, 2)  insert into post_post_comment (Post_id, comments_id) values (1, 3)  insert into post_post_comment (Post_id, comments_id) values (1, 4)
这样如果记录比较多,将会影响到系统性能。我们可以使用@JoinColumn来避免产生中间表:

@JoinColumn(name = "post_id")
但即使是没有中间表,系统任然会执行7条SQL语句:

insert into post (title, id) values ('First post', 1)  insert into post_comment (review, id) values ('My first review', 2)  insert into post_comment (review, id) values ('My second review', 3)  insert into post_comment (review, id) values ('My third review', 4)  update post_comment set post_id = 1 where id = 2  update post_comment set post_id = 1 where id =  3  update post_comment set post_id = 1 where id =  4
如果我们想删除一条从表记录

post.getComments().remove(0);
系统任然会执行2条语句:

update post_comment set post_id = null where post_id = 1 and id = 2 delete from post_comment where id=2
要想避免这种情况,就要使用@ManyToOne

@Entity(name = "Post")@Table(name = "post")public class Post {      @Id    @GeneratedValue    private Long id;      private String title;      @OneToMany(        mappedBy = "post",         cascade = CascadeType.ALL,         orphanRemoval = true    )    private List<PostComment> comments = new ArrayList<>();       public void addComment(PostComment comment) {        comments.add(comment);        comment.setPost(this);    }      public void removeComment(PostComment comment) {        comments.remove(comment);        comment.setPost(null);    }}  @Entity(name = "PostComment")@Table(name = "post_comment")public class PostComment {      @Id    @GeneratedValue    private Long id;      private String review;      @ManyToOne(fetch = FetchType.LAZY)    @JoinColumn(name = "post_id")    private Post post;       @Override    public boolean equals(Object o) {        if (this == o) return true;        if (!(o instanceof PostComment )) return false;        return id != null && id.equals(((PostComment) o).id);    }    @Override    public int hashCode() {        return 31;    }}

这样系统就只会产生4条SQL语句:

insert into post (title, id) values ('First post', 1)  insert into post_comment (post_id, review, id) values (1, 'My first review', 2)  insert into post_comment (post_id, review, id) values (1, 'My second review', 3)  insert into post_comment (post_id, review, id) values (1, 'My third review', 4)

删除一条从表记录

PostComment comment1 = post.getComments().get( 0 ); post.removeComment(comment1);
系统也只会执行1条SQL语句:

delete from post_comment where id = 2


但是这样同时使用@OneToMany和@ManyToOne要注意以下几点:

1. 在从表@ManyToOne中要使用FetchType.LAZY,否则会导致性能降低。

2. 主表中增加了2个方法,addComment和removeComment。

3. 从表重载了equals和hashCode方法。

4. 在使用Json来序列化对象时,会产生无限递归(Infinite recursion)的错误。这里有2个解决方法:

   a. 在@ManyToOne下面使用@JsonIgnore.

   b. 在@OneToMany下面使用@JsonManagedReference,在@ManyToOne下面使用@JsonBackReference

@JsonBackReference和@JsonManagedReference:@JsonBackReference标注的属性在序列化(serialization)时,会被忽略。@JsonManagedReference标注的属性则会被序列化。在序列化时,@JsonBackReference的作用相当于@JsonIgnore,此时可以没有@JsonManagedReference。但在反序列化(deserialization)时,如果没有@JsonManagedReference,则不会自动注入@JsonBackReference标注的属性;如果有@JsonManagedReference,则会自动注入@JsonBackReference标注的属性。  


@JsonIgnore:直接忽略某个属性,以断开无限递归,序列化或反序列化均忽略。当然如果标注在get、set方法中,则可以分开控制,序列化对应的是get方法,反序列化对应的是set方法。




阅读全文
0 0
原创粉丝点击