一个客户可以对应多个联系人
多个联系人可以属于同一个客户
使用外键。
在联系人表中添加一列,这一列的值来源于 客户表的主键,添加的这列
是外键。
从表:
多对一的关系映射:多个联系人对应一个客户
所以,从表实体包含主表的对象引用
private Customer customer;
主表:
1.一对多关系映射:一个客户对应多个联系人
主表中包含从表实体的引用集合
private Set<LinkMan> linKmans = new HashSet(0);
主表:
@OneToMany(targetEntity=LinkMan.class,mappedBy=”customer”)
Private Set<LinkMan> linkmans = new HashSet(0);
关联关系的维护:
在多表关系中,有一个很重要的概念叫做关联关系维护,也就是你中有我,我中有你,当一方数据有变动时会想着让对方也做相关的更新,但是这个事如果二者都去考虑操作比较不合理,那么我干脆让一方去维护这个事情,让谁呢? 让多的一方,也就是从表,因为他只需要维护一个对象 客户。
mappedBy: 关联关系维护,这个属性指向谁,就让谁放弃维护关联关系,如果不加,则会出现第三张表
从表:
@ManyToOne(targetEntity=Customer.class)
@JoinColumn(name=”lkm_cust_id”,referencedColumnName=”cust_id”)//增加一列外键列
主表类
package domain;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* Title: Customer
* Description: 客户的实体类
* @author zhaocq
* @date 2018年9月19日
*/
@Entity
@Table(name="cst_customer")
public class Customer implements Serializable {
@Id
@Column(name="cust_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer custId;
@Column(name="cust_name")
private String custName;
@Column(name="cust_source")
private String custSource;
@Column(name="cust_industry")
private String custIndustry;
@Column(name="cust_level")
private String custLevel;
@Column(name="cust_address")
private String custAddress;
@Column(name="cust_phone")
private String custPhone;
// 一对多(客户表中要包含一个联系集合)
@OneToMany(targetEntity=LinkMan.class,mappedBy="customer",cascade=CascadeType.REMOVE,fetch=FetchType.EAGER)
private Set<LinkMan> linkMams = new HashSet(0);
public Set<LinkMan> getLinkMams() {
return linkMams;
}
public void setLinkMams(Set<LinkMan> linkMams) {
this.linkMams = linkMams;
}
public Integer getCustId() {
return custId;
}
public void setCustId(Integer custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
@Override
public String toString() {
return "Customer [custId=" + custId + ", custName=" + custName + ", custSource=" + custSource
+ ", custIndustry=" + custIndustry + ", custLevel=" + custLevel + ", custAddress=" + custAddress
+ ", custPhone=" + custPhone + "]";
}
}
从表类
package domain;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
* Title: LinkMan
* Description: 联系人实体类
* @author zhaocq
* @date 2018年9月19日
*/
@Entity
@Table(name="cst_linkman")
public class LinkMan implements Serializable {
@Id
@Column(name="lkm_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer lkmId;
@Column(name="lkm_name")
private String lkmName;
@Column(name="lkm_gender")
private String lkmGender;
@Column(name="lkm_phone")
private String lkmPhone;
@Column(name="lkm_mobile")
private String lkmMobile;
@Column(name="lkm_email")
private String lkmEmail;
@Column(name="lkm_position")
private String lkmPosition;
@Column(name="lkm_memo")
private String lkmMemo;
// 多对一(联系人中包含客户对象的引用)
@ManyToOne(targetEntity=Customer.class,fetch=FetchType.LAZY)
@JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Integer getLkmId() {
return lkmId;
}
public void setLkmId(Integer lkmId) {
this.lkmId = lkmId;
}
public String getLkmName() {
return lkmName;
}
public void setLkmName(String lkmName) {
this.lkmName = lkmName;
}
public String getLkmGender() {
return lkmGender;
}
public void setLkmGender(String lkmGender) {
this.lkmGender = lkmGender;
}
public String getLkmPhone() {
return lkmPhone;
}
public void setLkmPhone(String lkmPhone) {
this.lkmPhone = lkmPhone;
}
public String getLkmMobile() {
return lkmMobile;
}
public void setLkmMobile(String lkmMobile) {
this.lkmMobile = lkmMobile;
}
public String getLkmEmail() {
return lkmEmail;
}
public void setLkmEmail(String lkmEmail) {
this.lkmEmail = lkmEmail;
}
public String getLkmPosition() {
return lkmPosition;
}
public void setLkmPosition(String lkmPosition) {
this.lkmPosition = lkmPosition;
}
public String getLkmMemo() {
return lkmMemo;
}
public void setLkmMemo(String lkmMemo) {
this.lkmMemo = lkmMemo;
}
@Override
public String toString() {
return "LinkMan [lkmId=" + lkmId + ", lkmName=" + lkmName + ", lkmGender=" + lkmGender + ", lkmPhone="
+ lkmPhone + ", lkmMobile=" + lkmMobile + ", lkmEmail=" + lkmEmail + ", lkmPosition=" + lkmPosition
+ ", lkmMemo=" + lkmMemo + "]";
}
}
package com.itheima.test;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import org.junit.Test;
import domain.Customer;
import domain.LinkMan;
import utils.JpaUtil;
public class OTMTest {
//增
@Test
public void test() {
EntityManager em = JpaUtil.createEntityManager();
Customer customer = new Customer();
customer.setCustName("客户1");
LinkMan linkMan = new LinkMan();
linkMan.setLkmName("联系人1");
customer.getLinkMams().add(linkMan);
linkMan.setCustomer(customer);
EntityTransaction tx = em.getTransaction();
tx.begin();
em.persist(customer);
em.persist(linkMan);
tx.commit();
}
/**
* 级联删除
*
* 从表:随便删
* 主表:
* 是否有引用:
* 有不让删
* 没有可以删
*/
@Test
public void test1(){
EntityManager em = JpaUtil.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Customer c = em.find(Customer.class, 1);
em.remove(c);
tx.commit();
em.close();
}
}
在增加的时候,要有一定的顺序,应该先添加主表对象,再增加从表对象
但是当我们先添加从表对象,再添加主表对象的时候,执行也能成功,但是会出现一句update语句,这是为什么呢?
这是由于mappedBy="customer"的作用,当我们为主表放弃维护关系,从表为维护关系的一方。此时如果先添加从表对象,通过debug可以看到,保存从表对象的时候,customer属性为null。而当我们在保存主表对象的时候,customer属性又出现了,这也就导致了缓存区与快照区的差异,缓存区有customer属性但是快照区没有,根据快照的特性,在我们提交的时候就会产生update语句来同步缓存区与快照区
而当我们先添加主表对象的时候,由于主表为放弃维护关系的一方,所以是忽略LinkMan集合为null。所以不会产生缓存区与快照区之间的差异,因此不会产生update语句
上述删除操作就是级联删除,如果不配置级联删除,对于存在外间关系的主表对象,不能直接删除
要在@OneToMany中配置cascade=CascadeType.REMOVE进行级联删除
按照需求实现功能,没有问题!
这是时候 将 mappedBy 属性去掉,就会发现,多出一张中间表:
分析原因:因为没有配置 关联关系维护 放弃的对象,所以两个对象都会进行关联关系维护所以各自产生一张表。
结论:不能双向级联删除,由于多对多表之间有引用,一旦级联删除,会把所有有关联的数据全部干掉。
当我们有一个实体对象时,根据该对象中的方法获取关联对象的数据。
要求:两个对象两个实体之间必须要有关联关系(四种关联关系)
出现的问题
1.为什么查询客户后再利用导航查询获取联系人的时候会出现两条SQL语句?
2.相反查询联系人后再用导航查询获取客户信息的时候会出现一条SQL语句?
分析原因:
考虑一个问题,当我们获取客户后要不要同时获取它下面的所有联系人?同样当获取联系人时要不要获取它所属的客户?这里就谈到一个加载策略的问题,当我们从一对多的角度考虑,没必要立刻获取多的一方的所有信息,我们需要什么就去加载什么就可以了,因为如果多的一方有可能会有很多数据,如果全部加载,必然会消耗巨大的内存。而从多对一的较多来考虑,当联系人信息查询之后,随之它所引用的客户信息也会立即加载,因为客户一方只有一条数据,不会造成太大的内存消耗,另外一般从表中的信息的完整性肯定要要主表信息的支持。
小结: 通过以上的分析,可以确定这是由jpa底层的加载策略所造成,它默认情况就这以上的效果,但是我们可以通过配置来控制加载策略。配置属性都是在四种关系的注解中加 fetch 属性,属性值EAGER:立即加载 LAZY:按需加载。
package com.itheima.test;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import org.junit.Test;
import domain.Customer;
import domain.LinkMan;
import utils.JpaUtil;
/**
* Title: TestQuery
* Description: 对象导航查询
* @author zhaocq
* @date 2018年9月19日
* 对象导航查询:
* 当获取一个对象,然后根据这个对象中提供的方法对关联信息进行查询。
*
* 分析:
* 以下输出结果是 当通过主表获取从表信息的时候用的是懒加载,当通过从表获取主表信息的时候是立即加载,jpa中默认情况就是这样的。
* 但是我们可以通过配置改变加载时机,在关系注解当中配置 fecth LAZY EAGER
*/
public class TestQuery {
/**
* Title: test
* Description: 对象导航查询1
* 现获取客户信息,然后再通过对象导航查询获取联系人信息
*/
@Test
public void test(){
EntityManager em = JpaUtil.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Customer c = em.find(Customer.class, 1);
Set<LinkMan> linkMams = c.getLinkMams();
for(LinkMan l:linkMams){
System.out.println(l);
}
}
/**
* Title: test1
* Description:对象导航查询2
* 现获取联系人信息,然后通过导航查询获取客户信息
*/
@Test
public void test1(){
EntityManager em = JpaUtil.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
LinkMan l = em.find(LinkMan.class, 1);
Customer c = l.getCustomer();
System.out.println(c);
}
}