范式
即不同的规范要求,在设计关系型数据库时,要遵从不同的规范要求,设计出合理的关系型数据库。
第一范式【1NF】:
具备原子性(最小单元,不可分割),主要是指表里的列,一个列一旦被创建后就不能再分开,一个列只能存放一个值。
第二范式【2NF】:
设计的表里面都应该要有一个唯一标识来区分表里每一行的数据,即主键。
第三范式【3NF】:
一个表里面尽量不要存放其他表的非关键性信息,即再表里存放外键。
单向一对多
1.1. 映射配置
@Entity
public class Product {
//多方
@Id
@GeneratedValue
private Long id;
private String name;
@Entity
public class ProductDir {
//一方
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany
// 必须配置外键id,否则会多生成一张表,形成多对多的关系
@JoinColumn(name = "dir_id")//设置外键
// 建议实例化,用的时候不需要在实例化,这里和单向多对一要求不同
private Set<Product> products = new HashSet<Product>();
结论:
不论是先保存一方再保存多方,还是先保存多方再保存一方,使用一对多的时候,它都会至少执行5条SQL语句完成保存功能(如下)。我们一般不使用单向一对多(原因:性能太差)
//配置关系
dir.getProducts().add(product1);
dir.getProducts().add(product2);
product1.setDir(dir);
product2.setDir(dir);
Hibernate: insert into ProductDir (name) values (?)
Hibernate: insert into Product (name) values (?)
Hibernate: insert into Product (name) values (?)
Hibernate: update Product set dir_id=? where id=?
Hibernate: update Product set dir_id=? where id=?
获取代码
用延迟加载提高性能的
修改成FetchType.EAGER后,不管有没有找类型项目的商品,它都会马上发送SQL来去查询数据。
但是这种做法严重影响性能。–关联(join)查询影响性能
在配置映射关系的时候如果是@ManyToOne(fetch=FetchType.LAZY),@OneToMany(fetch=FetchType.LAZY) ,@ManyToMany(fetch=FetchType.LAZY) 都是默认使用延迟加载提高性能的。
只有Many在后面都是使用延迟加载获取数据。
集合映射
因为Hibernate在创建了集合对象后是使用了它的的集合类PersistentSet来接收数据的(而不是我们写的那个HashSet)。如果我们使用接口声明(如Set),那么它的集合类PersistentSet也是实现了这个接口。所以它可以把这个类赋给Set。 但是我们使用HashSet,它们关系是平级的,不能进行转换,所以就出现错误了。
结论:声明集合的时候必须使用接口
级联
操作一方,导致另一方受到影响
级联保存的目的:
我们直接保存商品类别(如:ProductDir,一方),就把它对应的商品(Product,多方)也一起保存起来
级联的配置:
映射配置:
@OneToMany(cascade = CascadeType.PERSIST, mappedBy = "dir")
private Set<Product> products = new HashSet<Product>();
@OneToMany(cascade = CascadeType.PERSIST, mappedBy = “dir”)
1.mappedBy = "dir"表示一方的关系参照多方Prodcut属性dir来管理
2.cascade = CascadeType.PERSIST
3.必须两边都建立关系
// 只能由一方建立到多方的关系(设置外键)
dir.getProducts().add(product);
dir.getProducts().add(product2);
// 指建立多方到一方的关系
product.setDir(dir);
product2.setDir(dir);
4.entityManager.persist(dir);只能保存一方
级联删除
可能会遇到的各种情况
-
级联删除:删除一方,然后级联删除多方(危险操作)
-
从一方去删除一个解除关系(外键的值为null)的多方:先获取一方,在删除一个多方
-
从一方去删除所有解除关系的多方:先获取一方,在删除所有多方
1\级联删除:删除一方,然后级联删除多方(危险操作)
示例:删除商品分类(ProductDir,一方),它下面的所有商品(Product,多方)都要删除
如果我们直接删除的话,就发现报一个错(外键关系不能删除)
Cannot delete or update a parent row: a foreign key constraint fails (jpa
.product
, CONSTRAINT FK_dt353uy1bfcml55ixct2txdu2
FOREIGN KEY (dir_id
) REFERENCES productdir
(id
))
所以必须配置一个级联 cascade = CascadeType.REMOVE
@Test
//删除一方,然后级联删除多方(危险操作)
public void testDel() throws Exception