一、一对多添加

客户—>联系人(一对多)
客户Customer 实体类:

@Entity
@Table(name="cst_customer")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="cust_id")
    private Long custId;
    @Column(name="cust_address")
    private String custAddress;
    @Column(name="cust_industry")
    private String custIndustry;
    @Column(name="cust_level")
    private String custLevel;
    @Column(name="cust_name")
    private String custName;
    @Column(name="cust_phone")
    private String custPhone;
    @Column(name="cust_source")
    private String custSource;
    /**
     * 配置客户和联系人之间的关系(一对多关系)
     * 使用注解的形式配置多表关系
     *      1.声明关系
     *          @OneToMany : 配置一对多关系
     *              targetEntity :对方对象的字节码对象
     *      2.配置外键(中间表)
     *          @JoinColumn : 配置外键
     *                  name:外键字段名称
     *                  referencedColumnName:参照的主表的主键字段名称
     *  在客户实体类上(一的一方)添加了外键了配置,所以对于客户而言,也具备了维护外键的作用
     *
     */

    @OneToMany(targetEntity = LinkMan.class)
    @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();
	//getter and setter toString...
}

联系人

@Entity
@Table(name = "cst_linkman")
public class LinkMan {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "lkm_id")
    private Long 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
     *      1.配置表关系
     *          @ManyToOne:    配置多对一关系
     *          targetEntity:  对方的实体类字节码
     *      2.配置外键(中间表)
     *          @JoinColumn :  配置外键
     *              1、name = "lkm_cust_id" : 外键名称
     *              2、referencedColumnName = "cust_id": 主表的主键字段
     *              3、fetch : 配置关联对象的加载方式
     *                      EAGER :立即加载
     *                       LAZY :延迟加载
     *              fetch:取来;接来;到达;吸引
     *  配置外键的过程,配置到了多的一方,就会在多的一方维护外键
     *
     */
    @ManyToOne(targetEntity = Customer.class,fetch = FetchType.LAZY)
    @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
    private Customer customer;
	//getter and setter toString...
}

测试保存客户和联系人customer.getLinkMans().add(linkMan);

@Test
@Transactional //配置事务
@Rollback(false) //不自动回滚
public void testAdd() {
    //创建一个客户,创建一个联系人
    Customer customer = new Customer();
    customer.setCustName("饿了么");

    LinkMan linkMan = new LinkMan();
    linkMan.setLkmName("小明");
    /**
     * 配置了客户到联系人的关系
     *      从客户的角度上:发送两条insert语句,发送一条update语句更新数据库(更新外键)
     *      由于我们配置了客户到联系人的关系:客户可以对外键进行维护
     *
     * 当客户放弃维护外键时此执行此测试方法:则保存的联系人的外键为空
     */
    customer.getLinkMans().add(linkMan);
    customerDao.save(customer);
    linkManDao.save(linkMan);
}

发送两条insert语句,发送一条update语句更新数据库(更新外键)

springboot2 jpa join 多对多查询 spring data jpa 一对多_外键


测试保存客户和联系人linkMan.setCustomer(customer);

@Test
@Transactional //配置事务
@Rollback(false) //不自动回滚
public void testAdd1() {
    //创建一个客户,创建一个联系人
    Customer customer = new Customer();
    customer.setCustName("中国石油");
    LinkMan linkMan = new LinkMan();
    linkMan.setLkmName("小李");
    /**
     * 配置联系人到客户的关系(多对一)只发送了两条insert语句
     * 由于配置了联系人到客户的映射关系(多对一),联系人的外键不为空
     */
    linkMan.setCustomer(customer);
    customerDao.save(customer);
    linkManDao.save(linkMan);
}

只发送了两条insert语句,没有update语句

springboot2 jpa join 多对多查询 spring data jpa 一对多_外键_02


我们可以在Customer 一对多关系中在一的一放放弃对外键的维护,使用testAdd1()方法保存数据,若此时再用testAdd()方法去保存,保存的联系人的外键为空。

@Entity
@Table(name="cst_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="cust_id")
    private Long custId;
    @Column(name="cust_address")
    private String custAddress;
    @Column(name="cust_industry")
    private String custIndustry;
    @Column(name="cust_level")
    private String custLevel;
    @Column(name="cust_name")
    private String custName;
    @Column(name="cust_phone")
    private String custPhone;
    @Column(name="cust_source")
    private String custSource;
    /**
     * 放弃外键维护权
     * 1、mappedBy: 对方配置关系的属性名称
     * 2、cascade:  配置级联(可以配置到设置多表的映射关系的注解上)
     *          CascadeType.All    所有
     *        CascadeType.MERGE    更新
     *      CascadeType.PERSIST    保存
     *       CascadeType.REMOVE    删除
     *
     * 3、fetch : 配置关联对象的加载方式
     *          EAGER :立即加载
     *           LAZY :延迟加载
     */
    @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();
    //getter and setter toString...
}

二、级联添加

需要在操作主体的实体类上,配置cascade属性,具体配置参考上面代码中的注释信息

/**
 * 级联添加:保存一个客户的同时,保存客户的所有联系人
 *         需要在操作主体的实体类上,配置cascade属性
 */
@Test
@Transactional //配置事务
@Rollback(false) //不自动回滚
public void testCascadeAdd() {
    Customer customer = new Customer();
    customer.setCustName("百度");

    LinkMan linkMan = new LinkMan();
    linkMan.setLkmName("小李");

    linkMan.setCustomer(customer);
    customer.getLinkMans().add(linkMan);

    // 只保存客户,同时会保存联系人
    customerDao.save(customer);
}

发送了两条insert语句

springboot2 jpa join 多对多查询 spring data jpa 一对多_外键_03

三、级联删除

/**
 * 级联删除:删除2号客户的同时,删除2号客户的所有联系人
 */
@Test
@Transactional //配置事务
@Rollback(false) //不自动回滚
public void testCascadeRemove() {
    //1.查询1号客户
    Customer customer = customerDao.findOne(2l);
    //2.删除1号客户
    customerDao.delete(customer);
}

springboot2 jpa join 多对多查询 spring data jpa 一对多_Customer_04


springboot2 jpa join 多对多查询 spring data jpa 一对多_外键_05


执行测试方法testCascadeRemove(),发现执行了三条delete语句,删除了两个联系人,删除了客户

springboot2 jpa join 多对多查询 spring data jpa 一对多_Customer_06