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

  • 相关阅读:
    jquery中简易tab切换
    网页中用哪种空链接
    php中each()与list()函数
    转:const“变量”、define的常量和static 变量
    php错误收集
    php基础小知识
    初学深度学习(TensorFlow框架的心得and经验总结)自用环境的总结
    Python扩展模块——调用WindowsAPI(pywin32的简单使用)
    Python扩展模块——selenium的使用(定位、下载文件等)
    Python扩展模块——自动化(testlinkAPI的使用)
  • 原文地址:https://www.cnblogs.com/xwgcxk/p/9712153.html
Copyright © 2011-2022 走看看