史上最简单的JPA关联教程
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
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
getAddresses() {return addresses;
}
public void setAddresses(List
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
@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
return classifies;
}
public void setClassifies(List
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
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
return goodses;
}
public void setGoodses(List
this.goodses = goodses;
}
}
这里需要注意的是,虽然是两张表,但是在运行项目的时候会自动生成第三张关系映射表,表的名称和字段,就是@ManyToMany下面设置的字段和名称,还有表的外键也是在ForeignKey里面设置的。请求的结果如下所示:
这里有一个地方大家一定不要误解,我截图上面的只能查询本身,指的是我查询出本身这个实体类的时候,它所关联的实体类不会一起查询出来,但是如果用get实体类的方法,是可以查询所关联的数据的,这点大家不要误解了。
到这里关于JPA关联查询就介绍完毕了,下一节将介绍jpa中原生sql查询
项目GitHub地址:**https://github.com/1913045515/JPA**
还没有评论,来说两句吧...