zoukankan      html  css  js  c++  java
  • Spring Boot中@OneToMany与@ManyToOne几个需要注意的问题

    @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方法。

  • 相关阅读:
    js截取字符串区分汉字字母代码
    List 去处自定义重复对象方法
    63. Unique Paths II
    62. Unique Paths
    388. Longest Absolute File Path
    41. First Missing Positive
    140. Word Break II
    139. Word Break
    239. Sliding Window Maximum
    5. Longest Palindromic Substring
  • 原文地址:https://www.cnblogs.com/xwgcxk/p/9712153.html
Copyright © 2011-2022 走看看