一、JPA_映射单向多对一的关联关系
1、创建实体类
//订单
@Table(name="JPA_ORDER")
@Entity
public class Order {
private Integer id;
private String orderName;
private Customer customer;
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name="ORDER_NAME")
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
//映射多对一的关联关系
//使用 @ManyToOne 来映射多对一的关联关系
//使用 @JoinColumn 来映射外键 name:外键键名
@JoinColumn(name="CUSTOMER_ID")
@ManyToOne
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
测试类:
//数据表生成
@Test
public void testManyToOne(){
}
保存数据 :
保存多对一时,建议先保存1的一端,然后保存 n 的一端,这样不会多出额外的 UPDATE 语句
@Test
public void testManyToOnePersist(){
Customer customer = new Customer();
customer.setAge(15);
customer.setBirth(new Date());
customer.setCreatTime(new Date());
customer.setEmail("[email protected]");
customer.setLastName("EE");
Order order1 = new Order();
order1.setOrderName("O-EE-1");
Order order2 = new Order();
order2.setOrderName("O-EE-2");
//设置关联关系
order1.setCustomer(customer);
order2.setCustomer(customer);
//执行保存操作
entityManager.persist(customer);
entityManager.persist(order1);
entityManager.persist(order2);
}
输出的SQL语句 : 是3 条insert 语句
如果把执行保存操作中调换顺序
@Test
public void testManyToOnePersist(){
Customer customer = new Customer();
customer.setAge(15);
customer.setBirth(new Date());
customer.setCreatTime(new Date());
customer.setEmail("[email protected]");
customer.setLastName("GG");
Order order1 = new Order();
order1.setOrderName("g-GG-1");
Order order2 = new Order();
order2.setOrderName("g-GG-2");
//设置关联关系
order1.setCustomer(customer);
order2.setCustomer(customer);
//执行保存操作
entityManager.persist(order1);
entityManager.persist(order2);
entityManager.persist(customer);
那么执行结果: 【可以保存成功,SQL的变化】 三条insert 和两条update
这个时候外键是null 的 【下图 中 CUSTOMER_ID外键列的值 实际上为null 】
只有在保存外这个customer 之后,才知道外键列时谁,这个时候customer 才会有id; 【如下图】
然后jpa去维护关联关系,又额外有两个update。所以总结:
获取数据:
①、默认情况下,使用左外连接的方式来获取 n 的一端的对象和其关联的 1 的一端的对象
@Test
public void testManyToOneFind(){
Order order = entityManager.find(Order.class, 1);
System.out.println(order.getOrderName());
System.out.println(order.getCustomer().getLastName());
}
执行的结果: 【一条select 语句】
②、可使用 @ManyToOne 中的 fetch 属性来修改默认的关联属性的加载策略 【懒加载】
还是同样的测试 ,运行结果: 先生成Order 的信息 , 再打印Customer --查询customer 的语句 【两条SQL语句】
删除数据:
①、删除
@Test
public void testManyToOneRemove(){
Order order = entityManager.find(Order.class, 1);
entityManager.remove(order);
}
运行结果: 一个select 一个 delete
②、不能直接删除1 的一端,因为有外键关联
@Test
public void testManyToOneRemove(){
Customer customer = entityManager.find(Customer.class, 7);
entityManager.remove(customer);
}
修改数据:
@Test
public void testManyToOneUpdate(){
Order order = entityManager.find(Order.class, 2);
order.getCustomer().setLastName("FFF");
}
二、JPA_映射单向一对多的关联关系
生成数据表:
@Test
public void testOneToMany(){
}
保存数据:
单向 1-n 关联关系执行保存时,一定会多出UPDATE语句,因为n 的一端在插入时不会同时插入外键列
@Test
public void testOneToManyPersist(){
Customer customer = new Customer();
customer.setAge(18);
customer.setBirth(new Date());
customer.setCreatTime(new Date());
customer.setEmail("[email protected]");
customer.setLastName("ZZ");
Order order1 = new Order();
order1.setOrderName("O-ZZ-1");
Order order2 = new Order();
order2.setOrderName("O-ZZ-2");
//建立关联关系
customer.getOrders().add(order1);
customer.getOrders().add(order2);
//执行保存操作
entityManager.persist(customer);
entityManager.persist(order1);
entityManager.persist(order2);
}
结果是在控制台输出3条 insert 语句 和两条 update语句
查询数据:
①、默认对关联的多的一方使用懒加载的加载策略
@Test
public void testOneToManyFind(){
Customer customer = entityManager.find(Customer.class, 9);
System.out.println(customer.getLastName());
System.out.println(customer.getOrders().size());
}
②、可以使用 @OneToMany 的fetch 属性来修改默认的加载策略
测试:
@Test
public void testOneToManyFind(){
Customer customer = entityManager.find(Customer.class, 9);
System.out.println(customer.getLastName());
System.out.println(customer.getOrders().size());
}
运行结果变成了主外连接
删除数据:
①、默认情况下,若删除 1 的一端,则想把关联 n 的一端的外键置空,然后进行删除
@Test
public void testOneToManyRemove(){
Customer customer = entityManager.find(Customer.class, 9);
entityManager.remove(customer);
}
运行结果 : 查询,然后把外键制空 , 最后删除
②、可以通过修改 @OneToMany 的 cascade 属性来修改默认的删除策略
//默认情况下,若删除 1 的一端,则想把关联 n 的一端的外键置空,然后进行删除
//可以通过修改 @OneToMany 的 cascade 属性来修改默认的删除策略
@Test
public void testOneToManyRemove(){
Customer customer = entityManager.find(Customer.class, 8);
entityManager.remove(customer);
}
更新数据:
@Test
public void testOneToManyUpdate(){
Customer customer = entityManager.find(Customer.class, 11);
customer.getOrders().iterator().next().setOrderName("O-xxx-11");
}
三、JPA_映射双向一对多的关联关系 和双向多对一是一样的
1、实体类: Order 的实体类 加上 private Customer customer;,Customer 的实体类不变
@Table(name="JPA_ORDERS") //订单
@Entity
public class Order {
private Integer id;
private String orderName;
private Customer customer;
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name="ORDER_NAME")
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
@JoinColumn(name="CUSTOMER_ID")
@ManyToOne(fetch=FetchType.LAZY)
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
保存数据:
①、结论:若是双向1 - n 的关联关系,执行保存时:
若是先保存 n 的一端 , 再保存 1 的一端,默认情况下会多出 4 (n) 条 UPDATE 语句。
若是先保存 1 的一端,再保存 n 的一端,默认情况下会多出 2(n) 条 UPDATE 语句
@Test
public void testOneToManyDouble(){
Customer customer = new Customer();
customer.setAge(18);
customer.setBirth(new Date());
customer.setCreatTime(new Date());
customer.setEmail("[email protected]");
customer.setLastName("yy");
Order order1 = new Order();
order1.setOrderName("O-YY-1");
Order order2 = new Order();
order2.setOrderName("O-YY-2");
//建立关联关系
customer.getOrders().add(order1);
customer.getOrders().add(order2);
order1.setCustomer(customer);
order2.setCustomer(customer);
//执行保存操作
entityManager.persist(order1);
entityManager.persist(order2);
entityManager.persist(customer);
}
会有四条update 语句输出
②、控制台多出2条 UPDATE 语句
在进行双向 1-n 关联关系时,建议使用 n 的一方来维护关联关系,而1 的一方不维护关联关系,这样会有效的减少SQL语句。
@Test
public void testOneToManyDouble2(){
Customer customer = new Customer();
customer.setAge(18);
customer.setBirth(new Date());
customer.setCreatTime(new Date());
customer.setEmail("[email protected]");
customer.setLastName("ss");
Order order1 = new Order();
order1.setOrderName("O-SS-1");
Order order2 = new Order();
order2.setOrderName("O-SS-2");
//建立关联关系
customer.getOrders().add(order1);
customer.getOrders().add(order2);
order1.setCustomer(customer);
order2.setCustomer(customer);
//执行保存操作 =====》 更改顺序
entityManager.persist(order1);
entityManager.persist(order2);
entityManager.persist(customer);
}
结果大家自己去实现之后的控制台看吧 ,数据已经成功的保存在数据库里了。
③、注意:若在 1 的一端的 @OneToMany 中使用 mappedBy 属性,则 @OneToMany 端就不能再使用 @JoinColumn 属性了。