7、多表相关

7.1、多表相关操作

便利咱们的开发,导入lombok!


<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.22</version>
</dependency>

7.2、1对1

客户表——>账户表

【Spring Data JPA 系列】07、多表关联操作

完结:

1、装备相相联系!

@OneToOne // 单向相关,1对1!
@JoinColumn(name = "account_id") // 设置外键的字段名
private Account account;

pojo/Customer.java


package com.yykk.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
/**
 * @author yykk
 */
@Entity // 作为 hibernate实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "tb_Customer") // 装备数据库表的称号,实体类中特点和表中字段的映射联系!
public class Customer {
  /**
   * @Id:声明主键的装备
   * @GeneratedValue:装备主键的生成战略 strategy
   * GenerationType.IDENTITY :自增,mysql
   * * 底层数据库有必要支撑主动增加(底层数据库支撑的主动增加办法,对id自增)
   * GenerationType.SEQUENCE : 序列,oracle
   * * 底层数据库有必要支撑序列
   * GenerationType.TABLE : jpa供给的一种机制,经过一张数据库表的方式协助咱们完结主键自增
   * GenerationType.AUTO : 由程序主动的协助咱们挑选主键生成战略
   * @Column:装备特点和字段的映射联系 name:数据库表中字段的称号
   */
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  @Column(name = "cust_name")
  private String custName;//客户称号
  @Column(name = "cust_source")
  private String custSource;//客户来历
  @Column(name = "cust_level")
  private String custLevel;//客户等级
  @Column(name = "cust_industry")
  private String custIndustry;//客户所属职业
  @Column(name = "cust_phone")
  private String custPhone;//客户的联系办法
  @Column(name = "cust_address")
  private String custAddress;//客户地址
  // 单向相关,1对1!
  @OneToOne
  @JoinColumn(name = "account_id") // 设置外键的字段名
  private Account account;
}

2、装备相关操作!

pojo/Customer.java

package com.yykk.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
/**
 * @author yykk
 */
@Entity // 作为 hibernate实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "tb_Customer") // 装备数据库表的称号,实体类中特点和表中字段的映射联系!
public class Customer {
  /**
   * @Id:声明主键的装备
   * @GeneratedValue:装备主键的生成战略 strategy
   * GenerationType.IDENTITY :自增,mysql
   * * 底层数据库有必要支撑主动增加(底层数据库支撑的主动增加办法,对id自增)
   * GenerationType.SEQUENCE : 序列,oracle
   * * 底层数据库有必要支撑序列
   * GenerationType.TABLE : jpa供给的一种机制,经过一张数据库表的方式协助咱们完结主键自增
   * GenerationType.AUTO : 由程序主动的协助咱们挑选主键生成战略
   * @Column:装备特点和字段的映射联系 name:数据库表中字段的称号
   */
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  @Column(name = "cust_name")
  private String custName;//客户称号
  @Column(name = "cust_source")
  private String custSource;//客户来历
  @Column(name = "cust_level")
  private String custLevel;//客户等级
  @Column(name = "cust_industry")
  private String custIndustry;//客户所属职业
  @Column(name = "cust_phone")
  private String custPhone;//客户的联系办法
  @Column(name = "cust_address")
  private String custAddress;//客户地址
  /**
   * 单向相关,1对1!
   * cascade 设置枚举值:相关操作!
   * ALL、PERSIST、MERGE、REMOVE、REFRESH、DETACH
   * fetch:是否设置为懒加载
   *    LAZY 懒加载(知道用到目标才会进行查询!由于不是一切的相关目标,都需求用到)
   *    EAGER 了解加载 (默许)
   *  orphanRemoval:相关移除(通常在修正的时分会用到)
   *    一旦把相关的数据设置为null,或许修正为其他的相关数据,假如想删去数据,就能够设置为true!
   *  optional:设置相关的目标不能为null,默许为true!false不能为null
   *  mappedBy:将外键束缚指向另一方保护!(通常在双向相相联系中,会抛弃一方的外键束缚!)
   *    值 = 另一方的相关特点名!
   */
  @OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval = true,optional = false,mappedBy = "customer")
  @JoinColumn(name = "account_id") // 设置外键的字段名
  private Account account;
}

pojo/Account.java

package com.yykk.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Entity
@Table(name = "tb_account")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  private String username;
  private String password;
  @OneToOne
  @JoinColumn(name = "customer_id")
  private Customer customer;
}

3、测验!

package com.yykk.test;
import com.yykk.config.SpringDataJPAConfig;
import com.yykk.pojo.Account;
import com.yykk.pojo.Customer;
import com.yykk.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class OneToOneTest {
  @Autowired
  CustomerRepository repository;
  @Test
  public void test_ins(){
    // 初始化数据
    Account account = new Account();
    account.setUsername("admin");
    Customer customer = new Customer();
    customer.setCustName("admin");
    customer.setAccount(account);
    account.setCustomer(customer);
    repository.save(customer);
   }
  /**
   *  为什么懒加载需求装备业务:
   *  当经过repository调用网查询办法,session就会当即封闭,一旦session封闭就不能查询!
   *  加了业务之后,就能让session直到业务结束结束后才会封闭!
   */
  @Test
  @Transactional(readOnly = true)
  public void test_sel(){
    Optional<Customer> customer = repository.findById(16L); // 只查询出客户,session就封闭了!
    System.out.println("---------------------");
    System.out.println(customer.get());
   }
  @Test
  public void test_del(){
    repository.deleteById(1L);
   }
  @Test
  public void test_upd(){
    Customer customer = new Customer();
    customer.setId(17L);
    customer.setCustName("yykk");
    customer.setAccount(null);
    repository.save(customer);
   }
}

差异

这两个设置之间的却比在于对 断开联系,例如:当设置地址为null或另一个Address目标。

  • 假如指定了 orphanRemoval = true,则会主动删去断开连接的Address实例,这对于整理很有用没有一个不应该存在的相关目标(例如地址)来自一切者目标(例如员工)的引证。
  • 假如指定 cascade = CascadeType.REMOVE,则不会执行任何主动操作,由于断开联系不是删去操作

7.3、一对多

一个客户有多条信息

【Spring Data JPA 系列】07、多表关联操作
完结:

1、装备管理联系

@OneToMany

@JoinColumn(name = “customer_id”)

// 一对多
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "customer_id")
private List<Message> messages;

2、装备相相联系

pojo/Customer.java

package com.yykk.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.List;
/**
 * @author yykk
 */
@Entity // 作为 hibernate实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "tb_Customer") // 装备数据库表的称号,实体类中特点和表中字段的映射联系!
public class Customer {
  /**
   * @Id:声明主键的装备
   * @GeneratedValue:装备主键的生成战略 strategy
   * GenerationType.IDENTITY :自增,mysql
   * * 底层数据库有必要支撑主动增加(底层数据库支撑的主动增加办法,对id自增)
   * GenerationType.SEQUENCE : 序列,oracle
   * * 底层数据库有必要支撑序列
   * GenerationType.TABLE : jpa供给的一种机制,经过一张数据库表的方式协助咱们完结主键自增
   * GenerationType.AUTO : 由程序主动的协助咱们挑选主键生成战略
   * @Column:装备特点和字段的映射联系 name:数据库表中字段的称号
   */
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  @Column(name = "cust_name")
  private String custName;//客户称号
  @Column(name = "cust_source")
  private String custSource;//客户来历
  @Column(name = "cust_level")
  private String custLevel;//客户等级
  @Column(name = "cust_industry")
  private String custIndustry;//客户所属职业
  @Column(name = "cust_phone")
  private String custPhone;//客户的联系办法
  @Column(name = "cust_address")
  private String custAddress;//客户地址
  /**
   * 单向相关,1对1!
   * cascade 设置枚举值:相关操作!
   * ALL、PERSIST、MERGE、REMOVE、REFRESH、DETACH
   * fetch:是否设置为懒加载
   *    LAZY 懒加载(知道用到目标才会进行查询!由于不是一切的相关目标,都需求用到)
   *    EAGER 了解加载 (默许)
   *  orphanRemoval:相关移除(通常在修正的时分会用到)
   *    一旦把相关的数据设置为null,或许修正为其他的相关数据,假如想删去数据,就能够设置为true!
   *  optional:设置相关的目标不能为null,默许为true!false不能为null
   *  mappedBy:将外键束缚指向另一方保护!(通常在双向相相联系中,会抛弃一方的外键束缚!)
   *    值 = 另一方的相关特点名!
   */
  @OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval = true,mappedBy = "customer")
  @JoinColumn(name = "account_id") // 设置外键的字段名
  private Account account;
  // 一对多
  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name = "customer_id")
  private List<Message> messages;
}

pojo/Message.java

package com.yykk.pojo;
import lombok.Data;
import javax.persistence.*;
@Entity
@Table(name="tb_message")
@Data
public class Message {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  // 这儿假如手动添加了有参结构,就一定要加无参,不然查询会有问题!
  private String info;
  public Message() {
   }
  public Message(String info) {
    this.info = info;
   }
}

3、代码测验!

package com.yykk.test;
import com.yykk.config.SpringDataJPAConfig;
import com.yykk.pojo.Customer;
import com.yykk.pojo.Message;
import com.yykk.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class OneToManyTest {
  @Autowired
  CustomerRepository repository;
  @Test
  public void test_ins(){
    List<Message> messageList = new ArrayList<>();
    messageList.add(new Message("hello"));
    messageList.add(new Message("word"));
    Customer customer = new Customer();
    customer.setCustName("yykk");
    customer.setMessages(messageList);
    repository.save(customer);
   }
  /**
   * 一对多fetch默许便是LAZY!
   * LAZY过程:
   *  1、findById 指挥查询Customer和其他相关的当即加载!
   *  2、由于输出,会主动调用customer.toString()
   *  LAZY长处:提高查询功能!
   */
  @Test
  @Transactional(readOnly = true)
  public void test_upd(){
    Optional<Customer> id = repository.findById(2L);
    System.out.println("-------------------");
    System.out.println(id);
   }
  /**
   * 删去操作!设置cascade = CascadeType.ALL | REMOVE
   */
  @Test
  public void test_del(){
    repository.deleteById(4L);
   }
}

7.4、多对一

完结:

1、装备管理联系

@ManyToOne

@JoinColumn(name = “customer_id”)

// 多对一
@ManyToOne(cascade = {CascadeType.PERSIST,CascadeType.REMOVE})
@JoinColumn(name = "customer_id")
private Customer customer;

2、装备相相联系!

pojo/Customer.java

package com.yykk.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.List;
/**
 * @author yykk
 */
@Entity // 作为 hibernate实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "tb_Customer") // 装备数据库表的称号,实体类中特点和表中字段的映射联系!
public class Customer {
  /**
   * @Id:声明主键的装备
   * @GeneratedValue:装备主键的生成战略 strategy
   * GenerationType.IDENTITY :自增,mysql
   * * 底层数据库有必要支撑主动增加(底层数据库支撑的主动增加办法,对id自增)
   * GenerationType.SEQUENCE : 序列,oracle
   * * 底层数据库有必要支撑序列
   * GenerationType.TABLE : jpa供给的一种机制,经过一张数据库表的方式协助咱们完结主键自增
   * GenerationType.AUTO : 由程序主动的协助咱们挑选主键生成战略
   * @Column:装备特点和字段的映射联系 name:数据库表中字段的称号
   */
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  @Column(name = "cust_name")
  private String custName;//客户称号
  @Column(name = "cust_source")
  private String custSource;//客户来历
  @Column(name = "cust_level")
  private String custLevel;//客户等级
  @Column(name = "cust_industry")
  private String custIndustry;//客户所属职业
  @Column(name = "cust_phone")
  private String custPhone;//客户的联系办法
  @Column(name = "cust_address")
  private String custAddress;//客户地址
  /**
   * 单向相关,1对1!
   * cascade 设置枚举值:相关操作!
   * ALL、PERSIST、MERGE、REMOVE、REFRESH、DETACH
   * fetch:是否设置为懒加载
   *    LAZY 懒加载(知道用到目标才会进行查询!由于不是一切的相关目标,都需求用到)
   *    EAGER 了解加载 (默许)
   *  orphanRemoval:相关移除(通常在修正的时分会用到)
   *    一旦把相关的数据设置为null,或许修正为其他的相关数据,假如想删去数据,就能够设置为true!
   *  optional:设置相关的目标不能为null,默许为true!false不能为null
   *  mappedBy:将外键束缚指向另一方保护!(通常在双向相相联系中,会抛弃一方的外键束缚!)
   *    值 = 另一方的相关特点名!
   */
  @OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval = true,mappedBy = "customer")
  @JoinColumn(name = "account_id") // 设置外键的字段名
  private Account account;
  // 一对多
  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name = "customer_id")
  private List<Message> messages;
}

pojo/Message.java

package com.yykk.pojo;
import lombok.Data;
import javax.persistence.*;
@Entity
@Table(name="tb_message")
@Data
public class Message {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  // 这儿假如手动添加了有参结构,就一定要加无参,不然查询会有问题!
  private String info;
  // 多对一
  @ManyToOne(cascade = {CascadeType.PERSIST,CascadeType.REMOVE})
  @JoinColumn(name = "customer_id")
  private Customer customer;
  public Message() {
   }
  public Message(String info, Customer customer) {
    this.info = info;
    this.customer = customer;
   }
  public Message(String info) {
    this.info = info;
   }
  @Override
  public String toString() {
    return "Message{" +
        "id=" + id +
        ", info='" + info + ''' +
        ", customerId=" + customer.getId() +
        ", customerName=" + customer.getCustName() +
        '}';
   }
}

在这儿假如你在其中一个里面设置了JoinColumn,那么在另一个中能够不设置,当然设置了也没有问题!

3、设置repository

repositories/MessageRepository

package com.yykk.repositories;
import com.yykk.pojo.Customer;
import com.yykk.pojo.Message;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.List;
public interface MessageRepository extends PagingAndSortingRepository<Message,Long> {
  /**
   * 依据客户id查询一切信息!
   * 经过规定办法名来完结查询,需求经过相关特点来进行匹配!
   * 可是只能经过id来进行匹配
   */
  List<Message> findByCustomer(Customer customer);
}

4、测验!

package com.yykk.test;
import com.yykk.config.SpringDataJPAConfig;
import com.yykk.pojo.Customer;
import com.yykk.pojo.Message;
import com.yykk.repositories.MessageRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.ArrayList;
import java.util.List;
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ManyToOneTest {
  @Autowired
  MessageRepository repository;
  /**
   * 多对一刺进:
   *   当刺进多的数据的时分,运用多对一的相相联系是更加合适的!
   */
  @Test
  public void test_ins(){
    // 一
    Customer customer = new Customer();
    customer.setCustName("admin");
    // 多
    List<Message> list = new ArrayList<>();
    list.add(new Message("stay awake",customer));
    list.add(new Message("at all time",customer));
    repository.saveAll(list);
   }
  /**
   * 多对一:依据客户id查询对应的一切信息!
   * 这个在一对多完结更简单且合理 ,假如要在这儿完结就需求在repository中自定义!
   * 在这儿假如呈现了栈溢出StackOverFlow,解决方案:
   *   1、在pojo类中对toString办法进行重写!
   */
  @Test
  public void test_query(){
    Customer customer = new Customer();
    customer.setId(1L);
    customer.setCustName("xxx"); // 在这儿能够发现,不受其他条件的影响,只会依据id
    List<Message> messages = repository.findByCustomer(customer);
    // 这儿会隐式调用toString()
    System.out.println(messages);
   }
  @Test
  public void test_delete(){
    Customer customer = new Customer();
    customer.setId(1L);
    List<Message> messages = repository.findByCustomer(customer);
    // 这儿会隐式调用toString()
    repository.deleteAll(messages);
   }
}

7.5、多对多

【Spring Data JPA 系列】07、多表关联操作

1、装备管理联系

@ManyToMany

@JoinColumn(name=“customer_id”)

/**
 *  单向多对多
 *  中心表需求设置@JoinTable来保护外键(不设置也会主动生成!)
 *  name:指定中心表的表称号
 *  joinColumns:设置本表的外键称号
 *  inverseJoinColumns:设置相关表的外键称号
 * */
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
    name = "tb_customer_role",
    joinColumns = {@JoinColumn(name = "c_id")},
    inverseJoinColumns = {@JoinColumn(name = "r_id")}
)
private Set<Role> roles;

2、装备相相联系!

pojo/Customer.java

package com.yykk.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.List;
import java.util.Set;
/**
 * @author yykk
 */
@Entity // 作为 hibernate实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "tb_Customer") // 装备数据库表的称号,实体类中特点和表中字段的映射联系!
public class Customer {
  /**
   * @Id:声明主键的装备
   * @GeneratedValue:装备主键的生成战略 strategy
   * GenerationType.IDENTITY :自增,mysql
   * * 底层数据库有必要支撑主动增加(底层数据库支撑的主动增加办法,对id自增)
   * GenerationType.SEQUENCE : 序列,oracle
   * * 底层数据库有必要支撑序列
   * GenerationType.TABLE : jpa供给的一种机制,经过一张数据库表的方式协助咱们完结主键自增
   * GenerationType.AUTO : 由程序主动的协助咱们挑选主键生成战略
   * @Column:装备特点和字段的映射联系 name:数据库表中字段的称号
   */
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  @Column(name = "cust_name")
  private String custName;//客户称号
  @Column(name = "cust_source")
  private String custSource;//客户来历
  @Column(name = "cust_level")
  private String custLevel;//客户等级
  @Column(name = "cust_industry")
  private String custIndustry;//客户所属职业
  @Column(name = "cust_phone")
  private String custPhone;//客户的联系办法
  @Column(name = "cust_address")
  private String custAddress;//客户地址
  /**
   * 单向相关,1对1!
   * cascade 设置枚举值:相关操作!
   * ALL、PERSIST、MERGE、REMOVE、REFRESH、DETACH
   * fetch:是否设置为懒加载
   *    LAZY 懒加载(知道用到目标才会进行查询!由于不是一切的相关目标,都需求用到)
   *    EAGER 了解加载 (默许)
   *  orphanRemoval:相关移除(通常在修正的时分会用到)
   *    一旦把相关的数据设置为null,或许修正为其他的相关数据,假如想删去数据,就能够设置为true!
   *  optional:设置相关的目标不能为null,默许为true!false不能为null
   *  mappedBy:将外键束缚指向另一方保护!(通常在双向相相联系中,会抛弃一方的外键束缚!)
   *    值 = 另一方的相关特点名!
   */
  @OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval = true,mappedBy = "customer")
  @JoinColumn(name = "account_id") // 设置外键的字段名
  private Account account;
  // 一对多
  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name = "customer_id")
  private List<Message> messages;
  /**
   *  单向多对多
   *  中心表需求设置@JoinTable来保护外键(不设置也会主动生成!)
   *  name:指定中心表的表称号
   *  joinColumns:设置本表的外键称号
   *  inverseJoinColumns:设置相关表的外键称号
   * */
  @ManyToMany(cascade = CascadeType.ALL)
  @JoinTable(
      name = "tb_customer_role",
      joinColumns = {@JoinColumn(name = "c_id")},
      inverseJoinColumns = {@JoinColumn(name = "r_id")}
   )
  private Set<Role> roles;
}

pojo/Role.java

package com.yykk.pojo;
import javax.persistence.*;
@Entity
@Table(name = "tb_role")
public class Role {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  @Column(name = "role_name")
  private String rName;
  public Role(String rName) {
    this.rName = rName;
   }
  public Role(Long id, String rName) {
    this.id = id;
    this.rName = rName;
   }
  public Role() {
   }
}

3、创立repository!

package com.yykk.repositories;
import com.yykk.pojo.Role;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface RoleRepository extends PagingAndSortingRepository<Role,Long> {
}

4、测验!

package com.yykk.test;
import com.yykk.config.SpringDataJPAConfig;
import com.yykk.pojo.Customer;
import com.yykk.pojo.Role;
import com.yykk.repositories.CustomerRepository;
import com.yykk.repositories.RoleRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Commit;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ManyToManyTest {
  @Autowired
  CustomerRepository repository;
  @Autowired
  RoleRepository repositories;
  /**
   * 1、假如保存的数据,希望运用已有的,就需求从数据库中查出来!(耐久状态)、不然报错:游离状态不能耐久化!
   * 2、假如一个业务办法有多个耐久化操作,记得加上@Transactional,不然不能共用一个session
   * 3、在单元测验中,假如用到了@Transactional,假如有增删改操作就需求加 @Commit
   * 4、单元测验会以为你的业务办法@Transactional,仅仅进行测验,不会提交业务,需求独自加上@Commit
   */
  @Test
  @Transactional
  @Commit
  public void test_INSERT() {
    Set<Role> roles = new HashSet<>();
    roles.add(repositories.findById(2L).get());
    roles.add(repositories.findById(3L).get());
    Customer customer = new Customer();
    customer.setRoles(roles); // 只需设置了role,就需求设置相关操作!
    customer.setCustName("yykk");
    repository.save(customer);
   }
  @Test
  @Transactional(readOnly = true)
  public void test_QUERY() {
    System.out.println(repository.findById(5L));
   }
  /**
   * 多对多其实并不合适删去,应为经常呈现数据或许呈现和当时这一端相关还在另一端进行相关!
   * 此时进行删去就会呈现:ConstraintViolationException
   * 要进行删去,要确保没有额外的另一端数据相关
   */
  @Test
  @Transactional
  @Commit
  public void test_DELETE() {
    Optional<Customer> customer = repository.findById(5L);
    repository.delete(customer.get());
   }
}

多对多进行删去或许呈现的问题!

能够参考官网文档:docs.jboss.org/hibernate/o…

【Spring Data JPA 系列】07、多表关联操作