JPA 五種 對映關係
一、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 屬性了。
四、JPA_對映雙向一對一的關聯關係
五、JPA_對映雙向多對多的關聯關係