多表操作的级联相关#
一对多配置#
数据库表之间难免会出现彼此的约束, 如商品分类表和商品表之间,就是典型的一对多的关系,同一个分类下有多种不同的商品,下面就是jpa如何通过注解控制一对多的关系
- 双方都有一个彼此之间的引用, 如在one的一方,维护着多的一方的一个集合,一般使用HashSet,而在many的一方维护着一的一方的引用
- 在一的一方使用注解
@OneToMany
- 在多的一方使用注解
@ManyToOne
- 维护主键的一方需要使用
@JoinColumn(name = "customer_id",referencedColumnName = "id")
注解, 作用是指明外键列名,以及引用的主键列名
关于主键的维护:
一般我们会选在让多的一方维护外键,不是因为一的一方不能维护,在一对多的关系中,双方都可以进行主键的维护,并且我们把这种关系叫做双向管理,但是双方都维护主键,就会使得多出一条update语句,产生资源的浪费,原因如下:
所谓维护主键,就比如说我们通过jpa的save方法插入主表中的实体1和从表中的实体2,如果我们没有进行双方之间的关联,两条数据会被添加进数据库,但是外键部分却为null; 因此我们可以把维护主键看作是负责更新外键字段,这时如果双方都维护的话,就会出现两次update外键字段的sql
总结: 以下是OneToMany的最终方案
one:
mappedBy通过他指明,自己放弃维护外键,而参考Many端对外键的维护的实现 @OneToMany(mappedBy= "customer") private Set<LinkMan> linkManSet = new HashSet<>();
Many
targetEntity: 指明One的一方的字节码 name: 本表中的外键的列名, 因为在多的一方维护的外键 referencedColumnName: 外键引用的主键的列名 @ManyToOne(targetEntity: = Customer.class) @JoinColumn(name = "customer_id",referencedColumnName = "id") private Customer customer;
一对多的级联cascade
#
级联操作再One的一端进行配置
类型 | 作用 |
ALL | 级联所有(推荐) |
PERSIST | 保存 |
MERGE | 更新 |
REMOVE | 删除 |
@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
级联保存: 同时存在One和Many两个对象,我们在保存One的同时级联保存Many方的对象
级联删除:
情况1: One的一方在维护主键, 这是的级联删除就会分两步走 ,首先删除外键,然后删除One的一方,同时删除One级联的去全部Many方
情况2: One的一方不再维护主键,不能级联删除
多对多配置#
- 多对多配置中,同样需要一方主动的放弃对外键维护权
- 双方维护着代表对方的set集合
例子: User和Role 多对多的关系
在User端,主动放弃对外键的维护权
@ManyToMany(mappedBy = "users",cascade = CascadeType.ALL) public Set<Role> roles = new HashSet<>();
在Role端,维护着外键, 负责对中间表上外键的更新的操作
/** * 配置多对多 * 1. 声明关系的配置 * 2. 配置中间表(包含两个外键) * targetEntity: 对方的 实体类字节码 * */ @ManyToMany(targetEntity =User.class) @JoinTable( name = "user_role",// name 中间表名称 joinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")}, // 当前对象,在中间表中的外键名, 以及参照的本表的哪个主键名 inverseJoinColumns = {@JoinColumn(name = "sys_user_id", referencedColumnName = "user_id")} // 对方对象在中间表的外键 ) public Set<User> users = new HashSet<>();
对象导航查询#
所谓对象导航查询,就是首先使用jpa为我们提供的Repository查询得到结果对象,再通过该对象,使用该对象的get方法,进而查询出它关联的对象的操作
在一对多的关系中, get的属性是 Set集合, 而在多对一的关系中,get的属性是它维护的那个One端的引用
总结:
模式 | 作用 |
一查多 | 默认延迟加载,因为有可能一下子级联查询出成百上千的数据,但是我们却不用 |
多查一 | 默认立即查询,多查一条数据 |
如果想更改默认的加载模式, 就在@OneToMany(一的一方)注解上添加属性fetch = FetchType.EAGER
属性 | 作用 |
EAGER | 立即加载 |
LAZY | 延迟加载 |