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

摘要:
@如果OneToMany未添加@JoinColumn,系统将自动向主表和从表添加中间表。主表:@Entity(name=“Post”)公共类Post{@Id@GeneratedValue private Long Id;private String title;@OneToMany(cascade=Casca

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

免责声明:文章转载自《Spring Boot中@OneToMany与@ManyToOne几个需要注意的问题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇js简易函数性能测试器vi编辑器的使用(翻阅和编辑代码)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Moco模拟服务器post&amp;amp;get请求 (二)

1、moco启动命令如下:java -jar moco-runner-0.12.0-standalone.jar 协议类型 -p 端口号 -c json配置文件 2、带参数的get请求 [ { "request":{ "method":"get", "uri":"/api/get_event_list", "queri...

laravel框架使用生涯

手工安装laravel http://laravelacademy.org/resources-download 1、将下载的文件复制到虚拟主机目录 2、在Apache的配置文件配置一个虚拟主机【注意,需要指向 public目录下】 <VirtualHost *:80> DocumentRoot "C:phpStudyWWWlarav...

mybatis返回HashMap结果类型与映射

Xhtml代码  <!-- 返回HashMap结果 类型-->       <!-- 如果想返回JavaBean,只需将resultType设置为JavaBean的别名或全限定名 -->       <!-- TypeAliasRegistry类初始化时注册了一些常用的别名,如果忘记了别名可以在这里面查看 -->  ...

mybatis的关联查询以及count

1.多表查询,1对1的时候,最简单的做法 <resultMap id="postInfo" type="postInfoEntity"> <id property="postId" column="post_id"/> <result property="userName" column="us...

WebApi 传参详解(转)

一、无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax({type:"get"}) 来实现: 请求的后台Action方法仍为上篇文章中的GetUser() : 也可以用$.ajax({type:"get"}) 方式,正确的获得了返回数据: 二、传递一个参数的Get请求 通常我们需要传递参数只需要指定aja...

JAVA 传输post传输长字符、数据编码解码 反序列化字符串

JAVA 传输post传输长字符、数据编码解码 1.前段传输 这是传输的数组对象 2.后端接收格式已解码 JS代码: $.ajax({ url:prefix+"/importModelTree", data: {"modelId":modelId...