多表关联操作
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
一对一
客户表 —> 老婆表
客户表 —> 账户表
…
实现:
@OneToOne
@JoinColumn(name="外键字段名")
@OneToOne(mappedBy = "customer",cascade = {CascadeType.PERSIST,CascadeType.REMOVE})
@JoinColumn(name="wife_id")
private Wife wife;
wife
@Entity
@Table(name="tb_account")
@Data
/*@Getter // 生成所有属性的get方法
@Setter // 生成所有属性的set方法
@RequiredArgsConstructor // 生成final属性的构造函数, 如果没有final就是无参构造函数
@EqualsAndHashCode*/ public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
private String username;
private String password;
}
2.配置关联操作
// 单向关联 一对一
/*
* cascade 设置关联操作
* ALL, 所有持久化操作
PERSIST 只有插入才会执行关联操作
MERGE, 只有修改才会执行关联操作
REMOVE, 只有删除才会执行关联操作
fetch 设置是否懒加载
EAGER 立即加载(默认)
LAZY 懒加载( 直到用到对象才会进行查询,因为不是所有的关联对象 都需要用到)
orphanRemoval 关联移除(通常在修改的时候会用到)
一旦把关联的数据设置null ,或者修改为其他的关联数据, 如果想删除关联数据, 就可以设置true
optional 限制关联的对象不能为null
true 可以为null(默认 ) false 不能为null
mappedBy 将外键约束执行另一方维护(通常在双向关联关系中,会放弃一方的外键约束)
值= 另一方关联属性名
* */
@OneToOne(mappedBy = "customer",
cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval=true,optional=false)
// 设置外键的字段名
@JoinColumn(name="account_id")
private Account account;
}
测试 :
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class OneToOneTest {
@Autowired
CustomerRepository repository;
// 插入
@Test
public void testC(){
// 初始化数据
Account account = new Account(); account.setUsername("xushu");
Customer customer = new Customer();
customer.setCustName("张三");
customer.setAccount(account);
account.setCustomer(customer);
repository.save(customer);
}
// 插入
@Test
// 为什么懒加载要配置事务 :
// 当通过repository调用完查询方法,session就会立即关闭, 一旦session你就不能查询,
// 加了事务后, 就能让session直到事务方法执行完毕后才会关闭
@Transactional(readOnly = true) public void testR(){
Optional<Customer> customer = repository.findById(3L); // 只查询出客户, session关闭
System.out.println("================="); System.out.println(customer.get()); // toString
}
@Test
public void testD(){
repository.deleteById(1L);
}
@Test
public void testU(){
Customer customer = new Customer();
customer.setCustId(7L);
customer.setCustName("张三");
customer.setAccount(null);
repository.save(customer);
}
}
差异:
这两个设置之间的区别在于对断开关系。例如,当设置地址字段设置为null或另一个Address对象。
如果指定了 orphanRemovel = true , 则会自动删除断开连接的Address实例。这对于清理很有用 没有一个不应该存在的相关对象(例如地址) 来自所有者对象(例如员工)的引用。
如果仅指定 cascade = CascadeType.REMOVE , 则不会执行任何自动操作,因为断开关系不是删除操作
一对多
一个客户 有多条信息
1.配置管理关系
@OneToMany
@JoinColumn(name="customer_id")
@OneToMany
@JoinColumn(name="customer_id")
private List<Message> message;
2.配置关联操作
…
多对一
实现:
1.配置管理关系
@ManyToOne
@JoinColumn(name=“customer_id”)
@ManyToOne
@JoinColumn(name=“customer_id”)
private List message;
2.配置关联操作
…
多对多
1.配置管理关系
@ManyToMany
@JoinColumn(name=“customer_id”)
@ManyToMany
@JoinTable(name=“tb_customer_role”,joinColumns={@JoinColumn(name=“c_id”)},inverseJoinColumns={@JoinColumn(name=“r_i d”)})
private List roles;
2.配置关联操作
。。。
3.测试
// 保存
/*
1.如果保存的关联数据 希望使用已有的 ,就需要从数据库中查出来(持久状态)。否则 提示 游离状态不能持久化
2.如果一个业务方法有多个持久化操作, 记得加上@Transactional ,否则不能共用一个session
3. 在单元测试中用到了@Transactional , 如果有增删改的操作一定要加@Commit
4. 单元测试会认为你的事务方法@Transactional, 只是测试而已, 它不会为你提交事务, 需要单独加上 @Commit
*/
@Test
@Transactional
@Commit
public void testC() {
List<Role> roles=new ArrayList<>();
roles.add(roleRepository.findById(9L).get());
roles.add(roleRepository.findById(10L).get());
Customer customer = new Customer();
customer.setCustName("盘古");
customer.setRoles(roles);
repository.save(customer);
}
@Test
@Transactional(readOnly = true)
public void testR() {
System.out.println(repository.findById(14L));
//repository.save(customer);
}
/*
* 注意加上
* @Transactional
@Commit
多对多其实不适合删除, 因为经常出现数据出现可能除了和当前这端关联还会关联另一端,此时删除就会: ConstraintViolationException。
* 要删除, 要保证没有额外其他另一端数据关联
* */
@Test
@Transactional
@Commit
public void testD() {
Optional<Customer> customer = repository.findById(14L);
repository.delete(customer.get());
}