1. 單向一對多配置 單向一對多使用@OneToMany標簽進行配置,在一方有一個集合屬性與多方進行關聯,集合可以是List或者Set,區別是List是有序、Set是無序不重覆。 對應在一方配置@OneToMany: /** * 單向一對多:使用JPA配置 */ @Entity @Table(nam ...
1. 單向一對多配置
單向一對多使用@OneToMany標簽進行配置,在一方有一個集合屬性與多方進行關聯,集合可以是List或者Set,區別是List是有序、Set是無序不重覆。
對應在一方配置@OneToMany:
/** * 單向一對多:使用JPA配置 */ @Entity @Table(name = "t_productdir") public class ProductDir { @Id @GeneratedValue private Integer id; @Column(name = "dName") private String dirName; //產品分類名稱 /** * 單向一對多:在一方使用集合Set或者List進行多方關係的維護 * 對於集合,必須要先new出來 * * 對於資料庫:不管是多對一,還是一對多,不管是單向還是雙向, * 資料庫的設置都是不變的,哪邊是多方,外鍵就在哪邊 * 單向一對多,預設就是使用的懶載入(以後都把懶載入配置上) */ @OneToMany(fetch = FetchType.LAZY) @JoinColumn(name = "dir_id") @OrderBy("id desc") //需要排序的時候使用@OrderBy來拿值,多個排序屬性之間使用","分割,並且一定要用List集合 private Set<Product> productSet = new HashSet<>(); //集合預設懶載入 public ProductDir() { }
性能:單向一對多無論配置懶載入還是迫切載入都發送相同數量的SQL語句,性能極差。
2. 雙向一對多、多對一配置
2.1.基礎配置
雙向一對多、多對一需要同時配置兩邊的屬性,一方與多方都要有關聯屬性存在(同時配置@ManyToOne、@OneToMany),同時在一方放棄關係維護配置mappedBy。具體配置如下:
多方Product:
/** * 雙向一對多、多對一:使用JPA配置 */ @Entity @Table(name = "t_product") public class Product { @Id @GeneratedValue private Integer id; @Column(name = "t_name") private String name; //產品名稱 @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "dir_id") private ProductDir productDir; public ProductDir getProductDir() { return productDir; } public void setProductDir(ProductDir productDir) { this.productDir = productDir; } public Product() { } }
一方ProductDir:
/** * 雙向一對多、多對一:使用JPA配置 */ @Entity @Table(name = "t_productdir") public class ProductDir { @Id @GeneratedValue private Integer id; @Column(name = "dName") private String dirName; //產品分類名稱 //mappedBy:一方放棄關係維護,把關係維護交給多方,註意mappedBy中的值必須和Product中ProductDir的屬性一樣 //註意:使用mappedBy就不要使用JoinColumn了,這邊已經不需要維護關係了 @OneToMany(fetch = FetchType.LAZY, mappedBy = "productDir") //@JoinColumn(name = "dir_id") // @OrderBy("id desc") //需要排序的時候使用@OrderBy來拿值,多個排序屬性之間使用","分割,並且一定要用List集合 private Set<Product> productSet = new HashSet<>(); //集合預設懶載入 public ProductDir() { } }
2.2.級聯配置
在一方的多方屬性@OneToMany上使用cascade表示級聯,主要有以下幾種配置方式:
① Cascade=CascadeType.PERSIST:級聯保存;
② Cascade=CascadeType.REMOVE:級聯刪除(很危險);
③ Cascade=CascadeType.ALL:級聯增刪改
3. 單向多對多
多對多關係我們以保存2個用戶(user)、3個角色(role)來進行多對多的測試;
用戶與角色是多對多的關係,一個用戶對應多個角色,一個角色可以由多個用戶充當。
多堆多關係涉及到一張中間表user_role,
單向關係:通過用戶可以找到多個角色,而角色不能找到對應的用戶。
3.1.單向多對多配置
主表:User用戶類
/** * 基於單向多對多,在用戶方可以找到對應的角色(角色不能找到對應用戶),只需要在用戶方配置@ManyToMany註解映射 */ @Entity @Table(name="t_user") public class User { @GeneratedValue @Id private Long id; private String name; // @ManyToMany註釋表示User是多對多關係的一端。 // @JoinTable描述了多對多關係的中間表關係。name屬性指定中間表名稱, // joinColumns定義中間表與當前類User的外鍵關係。inverseJoinColumns定義中間表與關聯類Role的外鍵關係。 @ManyToMany @JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = { @JoinColumn(name = "role_id") }) private Set<Role> roles = new HashSet<Role>(); public User() { } public User(String name) { this.name = name; } }
從表:Role角色類
@Entity @Table(name="t_role") public class Role { @GeneratedValue @Id private Long id; private String name; public Role() { } public Role(String name) { this.name = name; } }
對應創建測試類:
/** * 保存2個用戶,保存3個角色(5條) */ @Test public void persistUserTest() { User user1 = new User("user1"); User user2 = new User("user2"); Role role1 = new Role("role1"); Role role2 = new Role("role2"); Role role3 = new Role("role3"); // 保存中間表:建立用戶到角色關係user1(role1,role2),user2(role1,role2,role3)(5條) user1.getRoles().add(role1); user1.getRoles().add(role2); user2.getRoles().add(role1); user2.getRoles().add(role2); user2.getRoles().add(role3); EntityManager entityManager = JPAUtil.getEntityManager(); entityManager.getTransaction().begin(); //保存用戶 entityManager.persist(user1); entityManager.persist(user2); // 保存角色 entityManager.persist(role1); entityManager.persist(role2); entityManager.persist(role3); entityManager.getTransaction().commit(); JPAUtil.close(entityManager); }
4. 雙向多對多
4.1.雙向多堆多配置
雙向多對多即是在兩方同時配置@ManyToMany註解,具體配置如下:
一方Role角色配置:
@Entity @Table(name="t_role") public class Role { @GeneratedValue(strategy = GenerationType.AUTO) @Id private Long id; private String name; // @ManyToMany註釋表示Role是多對多關係的一端。 @ManyToMany //joinColumns表示中間表與當前Role表的連接外鍵,inverseJoinColumns表示多方User與中間表的外鍵連接關係 @JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "role_id") }, inverseJoinColumns = { @JoinColumn(name = "user_id") }) private Set<User> userSet = new HashSet<>(); public Role() { } public Set<User> getUserSet() { return userSet; } public void setUserSet(Set<User> userSet) { this.userSet = userSet; } public Role(String name) { this.name = name; } }
多方User用戶配置:
/** * 基於單向多對多,在用戶方可以找到對應的角色(角色不能找到對應用戶),只需要在用戶方配置@ManyToMany註解映射 */ @Entity @Table(name="t_user") public class User { @GeneratedValue(strategy = GenerationType.AUTO) @Id private Long id; private String name; // @ManyToMany註釋表示User是多對多關係的一端。 // @JoinTable描述了多對多關係的中間表關係。name屬性指定中間表名稱, // joinColumns定義中間表與當前類User的外鍵關係。inverseJoinColumns定義中間表與關聯類Role的外鍵關係。 @ManyToMany @JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = { @JoinColumn(name = "role_id") }) private Set<Role> roles = new HashSet<Role>(); public User() { } public User(String name) { this.name = name; } }
5. 一對一配置
一對一場景在實際項目中用得比較少,這裡主要以QQ與QQ空間為例,有QQ才會有QQ空間。
5.1.唯一外鍵一對一
QQ類(主一)
@Entity public class QQ { @Id @GeneratedValue private Long id; private String number; // 一對一,一個qq號碼對應一個qq空間 @OneToOne(mappedBy="qq") private QQZone zone; }
QQ空間類(從一)
@Entity public class QQZone { @Id @GeneratedValue private Long id; private String name; // 一對一,一個qq空間屬於一個qq號碼 // 預設值optional = true表示qq_id可以為空;反之。。。 @OneToOne(optional = false) // unique=true確保了一對一關係 @JoinColumn(name = "qq_id", unique = true) private QQ qq; }
5.1.1保存數據測試
public void persist() throws Exception { QQ qq = new QQ(); qq.setNumber("123456"); QQZone zone = new QQZone(); zone.setName("楓夜"); // 建立關係 qq.setZone(zone); zone.setQq(qq); EntityManager entityManager = JPAUtils.getEntityManager(); entityManager.getTransaction().begin(); // 先保存主一 entityManager.persist(qq); entityManager.persist(zone); entityManager.getTransaction().commit(); entityManager.close(); }
5.2.共用主鍵一對一
QQ空間類(從一)
@Entity public class QQZone { @Id @GeneratedValue(generator = "fkGenerator") @GenericGenerator(name = "fkGenerator", strategy = "foreign", parameters = @Parameter(name = "property", value = "qq")) private Long id; private String name; // 一對一,一個qq空間輸入一個qq號碼 @OneToOne(optional = false) // 如果不加這個註解,添加QQZone信息時,就會自動在QQZone表中增加了一個外鍵qq_id @PrimaryKeyJoinColumn private QQ qq; }