前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >史上最简单的JPA关联教程

史上最简单的JPA关联教程

作者头像
林老师带你学编程
发布2019-05-26 00:33:35
1.7K0
发布2019-05-26 00:33:35
举报
文章被收录于专栏:强仔仔

JPA关联查询

因为项目中我们用到的都是双向管理关系,所以这边单向的我就不多做介绍。

我们这边接着上一节的课程继续介绍,这边我新建了Goods,GoodsDetail,Classify,Address四个实体映射类。分别进行一对一,一对多,多对多的关联介绍。

1.首先是一对一关系介绍,这边一对一的关系分别是Goods和GoodsDetail(商品表和商品详细表)

关联的注释为@OneToOne

Goods实体类:

package com.lzq.jpa.entity;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

import java.io.Serializable;

import java.util.ArrayList;

import java.util.List;

/**

* Created by qiang on 2018/1/22.

*/

@Entity

@Table(name="goods")

public class Goods implements Serializable {

@Id

@GenericGenerator(name = "PKUUID", strategy = "uuid2")

@GeneratedValue(generator = "PKUUID")

@Column(length = 36)

protected String id;

/**

* 名字

*/

@Column(name = "name", nullable = true, length = 30)

private String name;

@OneToOne(fetch = FetchType.LAZY,mappedBy="goods")

private GoodsDetail goodsDetail;

public Goods() {

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public GoodsDetail getGoodsDetail() {

return goodsDetail;

}

public void setGoodsDetail(GoodsDetail goodsDetail) {

this.goodsDetail = goodsDetail;

}

}

GoodsDetail实体类:

package com.lzq.jpa.entity;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

import java.io.Serializable;

/**

* Created by qiang on 2018/1/22.

*/

@Entity

@Table(name="goods_detail")

public class GoodsDetail implements Serializable {

@Id

@GenericGenerator(name = "PKUUID", strategy = "uuid2")

@GeneratedValue(generator = "PKUUID")

@Column(length = 36)

protected String id;

/**

* 名字

*/

@Column(name = "name", nullable = true, length = 30)

private String name;

@OneToOne(cascade=CascadeType.ALL)

@JoinColumn(name="goods_id")

private Goods goods;

public GoodsDetail() {

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Goods getGoods() {

return goods;

}

public void setGoods(Goods goods) {

this.goods = goods;

}

}

这边有一个问题是:如果采用这种双向的一对一关系就会产生【SSH异常系列】Cannot call sendError() after the response has been committed异常。因为goods会关联goodsDetail,然后goodsDetail会继续关联goods,这样就会产生死循环的问题。这边有三种解决办法,这边我就介绍一种解决办法,其它的大家可以参考下面这篇博客里介绍的方法:https://www.cnblogs.com/zr520/archive/2016/04/06/5357459.html

我这边介绍的方法是:在控制的一方添加:@JsonIgnore 注解,然后在实体类上面添加@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) 注解。如图所示:

但是这种方法也会有问题,就是设置JsonIgnore 的一方,是不能将所关联的数据查询出来的。

就比如上面goods只能查询到商品本身的信息,但是goodsDetail是不会关联查询出来的。但是没有设置JsonIgnore 的一方就会全部关联查询出来。这是这个方法的缺陷,可以采用其他的方法,方法就在上面给出的博客里面。

请求的结果如下所示:

2.接下来就是介绍双向一对多的关联查询了,这边我用用户实体类(user)和地址实体类(address)来做具体介绍,注解分别为@OneToMany和@ManyToOne(一对多和多对一)

用户实体类:

package com.lzq.jpa.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

import java.io.Serializable;

import java.util.List;

/**

* Created by qiang on 2018/1/22.

*/

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})

@Entity

@Table(name="user")

public class User implements Serializable {

@Id

@GenericGenerator(name = "PKUUID", strategy = "uuid2")

@GeneratedValue(generator = "PKUUID")

@Column(length = 36)

protected String id;

/**

* 名字

*/

@Column(name = "name", nullable = true, length = 30)

private String name;

/**

* 身高

*/

@Column(name = "height", nullable = true, length = 10)

private Integer height;

/**

* 用户所创建的地址信息

*/

@JsonIgnore

@OneToMany(cascade={CascadeType.ALL},fetch = FetchType.LAZY,mappedBy = "user")

private List<Address> addresses;

public User() {

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getHeight() {

return height;

}

public void setHeight(Integer height) {

this.height = height;

}

public List<Address> getAddresses() {

return addresses;

}

public void setAddresses(List<Address> addresses) {

this.addresses = addresses;

}

}

地址实体类:

package com.lzq.jpa.entity;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

import java.io.Serializable;

import java.util.List;

/**

* Created by qiang on 2018/1/22.

*/

@Entity

@Table(name="address")

public class Address implements Serializable {

@Id

@GenericGenerator(name = "PKUUID", strategy = "uuid2")

@GeneratedValue(generator = "PKUUID")

@Column(length = 36)

protected String id;

/**

* 名字

*/

@Column(name = "name", nullable = true, length = 30)

private String name;

/**

* 地址详情信息

*/

@Column(name = "detail", nullable = true, length = 100)

private String detail;

/**

* 地址所创建者的用户信息

*/

@ManyToOne

@JoinColumn(name = "user_id",foreignKey = @ForeignKey(name = "fk_user_id"))

private User user;

public Address() {

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getDetail() {

return detail;

}

public void setDetail(String detail) {

this.detail = detail;

}

public User getUser() {

return user;

}

public void setUser(User user) {

this.user = user;

}

}

这边也会存在循环关联的问题,我采用的方法也是通过JsonIgnore来解决的。mappedBy表示哪一方来主导,fetch = FetchType.LAZY表示进行懒加载,cascade={CascadeType.ALL}表示进行相应的关联操作。这些参数我会在实体类参数介绍的时候,具体给大家讲解的,这节课先不多做介绍。

请求的结果如下所示:

3.接下来最后的多对多查询,这边我用商品实体类(goods)和商品分类实体类(classify)给大家做细致的介绍。注解为:@ManyToMany

商品实体类(goods):

package com.lzq.jpa.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

import java.io.Serializable;

import java.util.ArrayList;

import java.util.List;

/**

* Created by qiang on 2018/1/22.

*/

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})

@Entity

@Table(name="goods")

public class Goods implements Serializable {

@Id

@GenericGenerator(name = "PKUUID", strategy = "uuid2")

@GeneratedValue(generator = "PKUUID")

@Column(length = 36)

protected String id;

/**

* 名字

*/

@Column(name = "name", nullable = true, length = 30)

private String name;

@ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.MERGE)

@JoinTable(name = "goods_classify_links",

joinColumns= { @JoinColumn(name = "goods_id", referencedColumnName = "id") }

, inverseJoinColumns = { @JoinColumn(name = "classify_id", referencedColumnName = "id") }

,inverseForeignKey = @ForeignKey(name = "fk_mr_links_goods_classify")

,foreignKey = @ForeignKey(name = "fk_mr_links_classify_goods"))

private List<Classify> classifies= new ArrayList<>();

@JsonIgnore

@OneToOne(fetch = FetchType.LAZY,mappedBy="goods")

private GoodsDetail goodsDetail;

public Goods() {

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public List<Classify> getClassifies() {

return classifies;

}

public void setClassifies(List<Classify> classifies) {

this.classifies = classifies;

}

public GoodsDetail getGoodsDetail() {

return goodsDetail;

}

public void setGoodsDetail(GoodsDetail goodsDetail) {

this.goodsDetail = goodsDetail;

}

}

商品分类实体类(classify):

package com.lzq.jpa.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

import java.io.Serializable;

import java.util.ArrayList;

import java.util.List;

/**

* Created by qiang on 2018/1/22.

*/

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})

@Entity

@Table(name="classify")

public class Classify implements Serializable {

@Id

@GenericGenerator(name = "PKUUID", strategy = "uuid2")

@GeneratedValue(generator = "PKUUID")

@Column(length = 36)

protected String id;

/**

* 名字

*/

@Column(name = "name", nullable = true, length = 30)

private String name;

@JsonIgnore

@ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.MERGE)

@JoinTable(name = "goods_classify_links",

joinColumns= { @JoinColumn(name = "goods_id", referencedColumnName = "id") }

, inverseJoinColumns = { @JoinColumn(name = "classify_id", referencedColumnName = "id") }

,inverseForeignKey = @ForeignKey(name = "fk_mr_links_goods_classify")

,foreignKey = @ForeignKey(name = "fk_mr_links_classify_goods"))

private List<Goods> goodses= new ArrayList<>();

public Classify() {

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public List<Goods> getGoodses() {

return goodses;

}

public void setGoodses(List<Goods> goodses) {

this.goodses = goodses;

}

}

这里需要注意的是,虽然是两张表,但是在运行项目的时候会自动生成第三张关系映射表,表的名称和字段,就是@ManyToMany下面设置的字段和名称,还有表的外键也是在ForeignKey里面设置的。

请求的结果如下所示:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018年01月26日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档