JPA學習(四、JPA_映射關聯關系)


框架學習之JPA(四)

JPA是Java Persistence API的簡稱,中文名Java持久層API,是JDK 5.0注解或XML描述對象-關系表的映射關系,並將運行期的實體對象持久化到數據庫中。

Sun引入新的JPA ORM規范出於兩個原因:其一,簡化現有Java EE和Java SE應用開發工作;其二,Sun希望整合ORM技術,實現天下歸一。

學習視頻:尚硅谷框架jpa學習(有興趣的同學留言郵箱)

使用軟件:eclipse

Java版本:jdk8

 

本節目錄

四、JPA_映射關聯關系

        1.映射單向多對一的關聯關系

        2.映射單向一對多的關聯關系

        3.映射雙向多對一的關聯關系

        4.映射雙向一對一的關聯關系

        5.映射雙向多對多的關聯關系

 

 

四、JPA_映射關聯關系

 

1.映射單向多對一的關聯關系

 

創建Order

 

package hue.edu.xiong.jpa;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.JoinColumn;

import javax.persistence.ManyToOne;

import javax.persistence.Table;

@Entity

@Table(name="JPA_ORDERS")

public class Order {

@Id

@GeneratedValue(strategy=GenerationType.AUTO)

private Integer id;

@Column(name="ORDER_NAME")

private String orderName;

//映射單向n-1的關聯關系

//使用@ManyToIne來映射多對一的關聯關系

//使用@JoinColumn來映射外鍵

    //上課學到的原則,對方永遠是一,即多個我對應一個對方,即多對一

@ManyToOne

@JoinColumn(name="CUSTOMER_ID")

private Customer customer;

//get,set略,請自行補充

}

  

 

保存測試:

@Test

public void testManyToOnePersist() {

Customer customer = new Customer();

customer.setAge(12);

customer.setEmail("937724308@qq.com");

customer.setLastName("xiong");

customer.setBirth(new Date());

customer.setCreatedTime(new Date());

Order order1 = new Order();

order1.setOrderName("O-FF-1");

Order order2 = new Order();

order2.setOrderName("O-FF-2");

//設置關聯關系

order1.setCustomer(customer);

order2.setCustomer(customer);

//執行保存操作

entityManager.persist(customer);

entityManager.persist(order1);

entityManager.persist(order2);

}

  

 

//修改保存順序

entityManager.persist(order1);

entityManager.persist(order2);

entityManager.persist(customer);

  

 

第一個測試會發現數據庫中是三個insert操作

 

第二個測試修改順序之后發現是三個insert操作,再是兩個update操作

 

保存多對一時,建議先保存1的一端,然后保存n的一端這樣不會有額外的update語句

 

獲取測試:

 

//默認情況下使用左外連接方式來獲取N的一端的對象和其關聯的1的一端的對象

//可使用@ManyToOne的fetch屬性來修改默認的關聯屬性的加載策略

@Test

public void testManyToOneFind() {

Order order = entityManager.find(Order.class, 1);

System.out.println(order.getOrderName());

System.out.println(order.getCustomer().getLastName());

}
------------------------------------------------------
//懶加載模式

//映射單向n-1的關聯關系

//使用@ManyToIne來映射多對一的關聯關系

//使用@JoinColumn來映射外鍵

//可使用@ManyToOne的fetch屬性來修改默認的關聯屬性的加載策略

@ManyToOne(fetch=FetchType.LAZY)

@JoinColumn(name="CUSTOMER_ID")

private Customer customer;

  

 

刪除測試:

 

//不能直接刪除 1 的一端, 因為有外鍵約束.

@Test

public void testManyToOneRemove(){

// Order order = entityManager.find(Order.class, 1);

// entityManager.remove(order);

Customer customer = entityManager.find(Customer.class, 5);

entityManager.remove(customer);

}

  

 

修改測試:

 

 

 

//可以修改外鍵對應的對象的值將"xiong"->"FFF"

@Test

public void testManyToOneUpdate(){

Order order = entityManager.find(Order.class, 2);

order.getCustomer().setLastName("FFF");

}

  

 

2.映射單向一對多的關聯關系

 

修改Order類,把Customer全部注解掉

 

package hue.edu.xiong.jpa;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

 

@Entity

@Table(name="JPA_ORDERS")

public class Order {

 

@Id

@GeneratedValue(strategy=GenerationType.AUTO)

private Integer id;

 

@Column(name="ORDER_NAME")

private String orderName;

 

// //映射單向n-1的關聯關系

// //使用@ManyToIne來映射多對一的關聯關系

// //使用@JoinColumn來映射外鍵

// //可使用@ManyToOne的fetch屬性來修改默認的關聯屬性的加載策略

// @ManyToOne(fetch=FetchType.LAZY)

// @JoinColumn(name="CUSTOMER_ID")

// private Customer customer;

//get,set略,請自行補充

}

  

 

 

修改Customer類,增加Set<Order> orders,並且設置一對多關系

 

package hue.edu.xiong.jpa;

 

import java.util.Date;

import java.util.Set;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.JoinColumn;

import javax.persistence.OneToMany;

import javax.persistence.Table;

import javax.persistence.Temporal;

import javax.persistence.TemporalType;

@Table(name = "JPA_CUSTOMERS")

@Entity

public class Customer {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

private Integer id;

@Column(name = "LAST_NAME")

private String lastName;

private String email;

private Integer age;

@Temporal(TemporalType.DATE)

private Date birth;

@Temporal(TemporalType.TIMESTAMP)

private Date createdTime;

 

//設置單向1-n關聯關系

@OneToMany

@JoinColumn(name="CUSTOMER_ID")

private Set<Order> orders;

}

 

 

保存測試:

 

//單向 1-n 關聯關系執行保存時, 一定會多出 UPDATE 語句.

//因為 n 的一端在插入時不會同時插入外鍵列.

@Test

public void testOneToManyPersist(){

Customer customer = new Customer();

customer.setAge(18);

customer.setBirth(new Date());

customer.setCreatedTime(new Date());

customer.setEmail("mm@163.com");

customer.setLastName("MM");

 

Order order1 = new Order();

order1.setOrderName("O-MM-1");

 

Order order2 = new Order();

order2.setOrderName("O-MM-2");

 

//建立關聯關系

customer.getOrders().add(order1);

customer.getOrders().add(order2);

 

//執行保存操作

entityManager.persist(customer);

 

entityManager.persist(order1);

entityManager.persist(order2);

}

 

  • 單向 1-n 關聯關系執行保存時, 一定會多出 UPDATE 語句.
  • 因為 n 的一端在插入時不會同時插入外鍵列.

 

查找測試:

 

//默認對關聯的多的一方使用懶加載的加載策略.

//可以使用 @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 的一端的外鍵置空, 然后進行刪除.

//可以通過 @OneToMany 的 cascade 屬性來修改默認的刪除策略.

@Test

public void testOneToManyRemove(){

Customer customer = entityManager.find(Customer.class, 8);

entityManager.remove(customer);

}

  

 

 

//設置單向1-n關聯關系

//使用 @OneToMany 來映射 1-n 的關聯關系

//使用 @JoinColumn 來映射外鍵列的名稱

//可以使用 @OneToMany 的 fetch 屬性來修改默認的加載策略

//可以通過 @OneToMany 的 cascade 屬性來修改默認的刪除策略.

@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE})

@JoinColumn(name="CUSTOMER_ID")

private Set<Order> orders;
  • 將外鍵修改為空之后再刪除
  • 將外鍵全部刪除之后再刪除

 

修改測試:

 

@Test

public void testUpdate(){

Customer customer = entityManager.find(Customer.class, 10);

 

customer.getOrders().iterator().next().setOrderName("O-XXX-10");

}

  

 

3.映射雙向多對一的關聯關系

 

  • 若是雙向 1-n 的關聯關系, 執行保存時
  • 若先保存 n 的一端, 再保存 1 的一端, 默認情況下, 會多出 n UPDATE 語句.
  • 若先保存 1 的一端, 則會多出 n UPDATE 語句
  • 在進行雙向 1-n 關聯關系時, 建議使用 n 的一方來維護關聯關系,  1 的一方不維護關聯系, 這樣會有效的減少 SQL 語句.
  • 注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 屬性, @OneToMany 端就不能再使用 @JoinColumn屬性了.
  • 放棄維護關聯關系,不使用JoinColumn標簽,在@OneToMany 中使用 mappedBy 屬性
// @JoinColumn(name="CUSTOMER_ID")

@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE},mappedBy="customer")

 

自我理解,就是把上面兩個關系組合起來,盡量使用多對一的關系,其他都一樣

 

 

 

4.映射雙向一對一的關聯關系

 

創建兩個類ManagerDepartment

 

package hue.edu.xiong.jpa;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.FetchType;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.OneToOne;

import javax.persistence.Table;

 

@Table(name = "JPA_MANAGERS")

@Entity

public class Manager {

@Id

@GeneratedValue

private Integer id;

@Column(name = "MGR_NAME")

private String mgrName;

// 對於不維護關聯關系, 沒有外鍵的一方, 使用 @OneToOne 來進行映射, 建議設置 mappedBy=true

@OneToOne(mappedBy = "mgr")

private Department dept;

 

//get,set略,請自行補充

}

 

 

  

package hue.edu.xiong.jpa;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.FetchType;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.JoinColumn;

import javax.persistence.OneToOne;

import javax.persistence.Table;

 

@Table(name = "JPA_DEPARTMENTS")

@Entity

public class Department {

@Id

@GeneratedValue

private Integer id;

@Column(name = "DEPT_NAME")

private String deptName;

// 使用 @OneToOne 來映射 1-1 關聯關系。

// 若需要在當前數據表中添加主鍵則需要使用 @JoinColumn 來進行映射. 注意, 1-1 關聯關系, 所以需要添加 unique=true

@JoinColumn(name = "MGR_ID", unique = true)

@OneToOne(fetch = FetchType.LAZY)

private Manager mgr;

 

//get,set略,請自行補充

 

}

  

 

保存測試:

 

//雙向 1-1 的關聯關系, 建議先保存不維護關聯關系的一方, 即沒有外鍵的一方, 這樣不會多出 UPDATE 語句.

@Test

public void testOneToOnePersistence(){

Manager mgr = new Manager();

mgr.setMgrName("M-BB");

 

Department dept = new Department();

dept.setDeptName("D-BB");

 

//設置關聯關系

mgr.setDept(dept);

dept.setMgr(mgr);

 

//執行保存操作

entityManager.persist(mgr);

entityManager.persist(dept);

}

  

 

  • l雙向 1-1 的關聯關系, 建議先保存不維護關聯關系的一方, 即沒有外鍵的一方, 這樣不會多出 UPDATE 語句.

 

查找測試:

//1.默認情況下, 若獲取維護關聯關系的一方, 則會通過左外連接獲取其關聯的對象.

//但可以通過 @OntToOne 的 fetch 屬性來修改加載策略.

@Test

public void testOneToOneFind(){

Department dept = entityManager.find(Department.class, 1);

System.out.println(dept.getDeptName());

System.out.println(dept.getMgr().getClass().getName());

}

  

//1. 默認情況下, 若獲取不維護關聯關系的一方, 則也會通過左外連接獲取其關聯的對象.

//可以通過 @OneToOne 的 fetch 屬性來修改加載策略. 但依然會再發送 SQL 語句來初始化其關聯的對象

//這說明在不維護關聯關系的一方, 不建議修改 fetch 屬性.

@Test

public void testOneToOneFind2(){

Manager mgr = entityManager.find(Manager.class, 1);

System.out.println(mgr.getMgrName());

 

System.out.println(mgr.getDept().getClass().getName());

}

 

 

 

5.映射雙向多對多的關聯關系

 

創建兩個類itemCategory

 

package hue.edu.xiong.jpa;

 

import java.util.HashSet;

import java.util.Set;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.JoinColumn;

import javax.persistence.JoinTable;

import javax.persistence.ManyToMany;

import javax.persistence.Table;

 

@Table(name="JPA_ITEMS")

@Entity

public class Item {

 

@Id

@GeneratedValue

private Integer id;

@Column(name="ITEM_NAME")

private String itemName;

 

//使用 @ManyToMany 注解來映射多對多關聯關系

//使用 @JoinTable 來映射中間表

//1. name 指向中間表的名字

//2. joinColumns 映射當前類所在的表在中間表中的外鍵

//2.1 name 指定外鍵列的列名

//2.2 referencedColumnName 指定外鍵列關聯當前表的哪一列

//3. inverseJoinColumns 映射關聯的類所在中間表的外鍵

@JoinTable(name="ITEM_CATEGORY",

joinColumns={@JoinColumn(name="ITEM_ID", referencedColumnName="ID")},

inverseJoinColumns={@JoinColumn(name="CATEGORY_ID", referencedColumnName="ID")})

@ManyToMany

private Set<Category> categories = new HashSet<>();

//get,set略,請自行補充

}

 

  

package hue.edu.xiong.jpa;

 

import java.util.HashSet;

import java.util.Set;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.ManyToMany;

import javax.persistence.Table;

 

@Table(name = "JPA_CATEGORIES")

@Entity

public class Category {

 

@Id

@GeneratedValue

private Integer id;

@Column(name = "CATEGORY_NAME")

private String categoryName;

@ManyToMany(mappedBy = "categories")

private Set<Item> items = new HashSet<>();

//get,set略,請自行補充,過分了啊,這個顏色一直調整不好

}

  

 

必須指定中間表

 

  • 使用 @ManyToMany 注解來映射多對多關聯關系
  • 使用 @JoinTable 來映射中間表
    • name 指向中間表的名字
    • joinColumns 映射當前類所在的表在中間表中的外鍵
      • name 指定外鍵列的列名
      • referencedColumnName 指定外鍵列關聯當前表的哪一列
    • inverseJoinColumns 映射關聯的類所在中間表的外鍵

 

典型多對多,一個學生對應多門課程,一門課程對應多個學生,學生加課程決定成績

 

保存案例:

 

//多對多的保存

@Test

public void testManyToManyPersist(){

Item i1 = new Item();

i1.setItemName("i-1");

 

Item i2 = new Item();

i2.setItemName("i-2");

 

Category c1 = new Category();

c1.setCategoryName("C-1");

 

Category c2 = new Category();

c2.setCategoryName("C-2");

 

//設置關聯關系

i1.getCategories().add(c1);

i1.getCategories().add(c2);

 

i2.getCategories().add(c1);

i2.getCategories().add(c2);

 

c1.getItems().add(i1);

c1.getItems().add(i2);

 

c2.getItems().add(i1);

c2.getItems().add(i2);

 

//執行保存

entityManager.persist(i1);

entityManager.persist(i2);

entityManager.persist(c1);

entityManager.persist(c2);

}

 

 

查找案例:

 

//對於關聯的集合對象, 默認使用懶加載的策略.

//使用維護關聯關系的一方獲取, 還是使用不維護關聯關系的一方獲取, SQL 語句相同.

@Test

public void testManyToManyFind(){

// Item item = entityManager.find(Item.class, 5);

// System.out.println(item.getItemName());

//

// System.out.println(item.getCategories().size());

 

Category category = entityManager.find(Category.class, 3);

System.out.println(category.getCategoryName());

System.out.println(category.getItems().size());

}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM