JPA规范:一对多、一对一、多对多的双向关联与级联操作以及JPA联合主键
通常在企業開發中,開發Dao層有兩種做法:?
(1)先建表,后再根據表來編寫配置文件和實體bean。使用這種方案的開發人員受到了傳統數據庫建模的影響。?
(2)先編寫配置文件和實體bean,然后再生成表,使用這種方案的開發人員采用的是領域建模思想,這種思想相對前一種思想更加OOP。
建議使用第二種(領域建模思想),從軟件開發來想,這種思想比第一種思想更加面向對象。 領域建模思想也是目前比較新的一門建模思想,第一種是傳統的建模思想,已經有10來年的發展歷程了,而領域建模思想是近幾年才興起的,這種思想更加的面向對象。
?
?
一、一對多雙向關聯與級聯操作:
以訂單類和訂單商品類為例:
多的一方為關系維護端,關系維護端負責外鍵記錄的更新,關系被維護端是沒有權利更新外鍵記錄。
1、訂單類:
@Entity public class Orders {private String orderid;private Float amount = 0f;private Set<OrderItem> items=new HashSet<OrderItem>();@Id @Column(length=12)public String getOrderid() {return orderid;}public void setOrderid(String orderid) {this.orderid = orderid;}@Column(nullable=false)public Float getAmount() {return amount;}public void setAmount(Float amount) {this.amount = amount;}//REFRESH,級聯刷新(調用refresh方法才會起作用);PERSIST,級聯保存(persist);//MERGE,級聯更新(merge方法);REMOVE,級聯刪除(remove方法);//級聯:cascade={CascadeType.ALL})如果要使用上面四項的使用,可以使用ALL來代替//@OneToMany默認行為是延遲加載//mappedBy:指定關系被維護端,指定OrderItem里面的order,相當于hibernate的inverse放棄維護@OneToMany(cascade={CascadeType.REFRESH,CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE},fetch=FetchType.LAZY,mappedBy="orders")public Set<OrderItem> getItems() {return items;}public void setItems(Set<OrderItem> items) {this.items = items;}public void addOrderItem(OrderItem orderItem){orderItem.setOrders(this);this.items.add(orderItem);} }2、訂單列表類:
@Entity public class OrderItem {private Integer id;private String productName;private Float sellPrice = 0f;private Orders orders;//對應Order類里面指定的關系被維護端@Id @GeneratedValuepublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(length=40,nullable=false)public String getProductName() {return productName;}public void setProductName(String productName) {this.productName = productName;}@Column(nullable=false)public Float getSellPrice() {return sellPrice;}public void setSellPrice(Float sellPrice) {this.sellPrice = sellPrice;}//默認立即加載//optional=true,選項允許為null,false時,不能為null@ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},optional=false)@JoinColumn(name="order_id")//設置外鍵名稱public Orders getOrders() {return orders;}public void setOrders(Orders orders) {this.orders = orders;} }3、一對多的測試類:
//JPA的Dao層 @Transactional public class JpaDaoImpl implements JpaDao {//事務管理@PersistenceContextprivate EntityManager em;//JPA一對多測試類@Overridepublic void jpaTest() {Orders orders=new Orders();orders.setAmount(34f);orders.setOrderid("999");OrderItem orderItem1=new OrderItem();orderItem1.setProductName("籃球");orderItem1.setSellPrice(150f);OrderItem orderItem2=new OrderItem();orderItem2.setProductName("足球");orderItem2.setSellPrice(90f);orders.addOrderItem(orderItem1);orders.addOrderItem(orderItem2);em.merge(orders);} }由于配置了事務管理,這里就不需要手動開啟、提交事務和關閉資源等重復的代碼,直接交由事務進行管理。
具體配置步驟可以參看這篇博客:https://blog.csdn.net/a745233700/article/details/81415550
?
?
二、一對一雙向關聯與級聯操作:
以身份證類和人為例:
1、Persion類:
@Entity public class Person {public Person() {}public Person(String name) {this.name=name;}private Integer id;private String name;private IDcard idcard;@Id @GeneratedValuepublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(length=10,nullable=false)public String getName() {return name;}public void setName(String name) {this.name = name;}//一對一配置@OneToOne(optional=false,cascade={CascadeType.ALL})@JoinColumn(name="idcard_id")public IDcard getIdcard() {return idcard;}public void setIdcard(IDcard idcard) {this.idcard = idcard;} }2、IDcard類:
@Entity public class IDcard {public IDcard() {}public IDcard(String cardno) {this.cardno = cardno;}private Integer id;private String cardno;private Person person;@Id @GeneratedValuepublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(length=18,nullable=false)public String getCardno() {return cardno;}public void setCardno(String cardno) {this.cardno = cardno;}//一對一配置:@OneToOne(mappedBy="idcard",cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH})public Person getPerson() {return person;}public void setPerson(Person person) {this.person = person;} }3、一對一測試類:
//JPA一對多測試類@Overridepublic void jpaTest() {Person person=new Person("小張"); person.setIdcard(new IDcard("448xxx1990xxxx1234"));em.persist(person);}?
?
三、多對多雙向關聯與級聯操作:
以教師類和學生類為例:
1、教師類:
//老師為關系被維護端 @Entity public class Teacher {public Teacher(){}public Teacher(String name) {this.name = name;}private Integer id;private String name;private Set<Student> students=new HashSet<Student>();@Id @GeneratedValuepublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(length=10,nullable=false)public String getName() {return name;}public void setName(String name) {this.name = name;}@ManyToMany(cascade=CascadeType.REFRESH,mappedBy="teachers")public Set<Student> getStudents() {return students;}public void setStudents(Set<Student> students) {this.students = students;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((id == null) ? 0 : id.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Teacher other = (Teacher) obj;if (id == null) {if (other.id != null)return false;} else if (!id.equals(other.id))return false;return true;} }2、學生類:
//學生為關系維護端 @Entity public class Student {public Student(){}public Student(String name) {this.name = name;}private Integer id;private String name;private Set<Teacher> teachers=new HashSet<Teacher>();@Id @GeneratedValuepublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(length=10,nullable=false)public String getName() {return name;}public void setName(String name) {this.name = name;}@ManyToMany(cascade=CascadeType.REFRESH)@JoinTable(name="student_teacher",//設置第三張表的表名inverseJoinColumns=@JoinColumn(name="teacher_id"),//設置被維護端在第三張表中的外鍵名稱joinColumns=@JoinColumn(name="student_id"))//設置維護端在第三張表中的外鍵名稱public Set<Teacher> getTeachers() {return teachers;}public void setTeachers(Set<Teacher> teachers) {this.teachers = teachers;}public void addTeacher(Teacher teacher){this.teachers.add(teacher);}public void removeTeacher(Teacher teacher){if(this.teachers.contains(teacher)){this.teachers.remove(teacher);}} }3、多對多測試類:
//JPA多對多測試類:沒有建立關系聯系的添加@Overridepublic void jpaTest() {//沒有建立關系聯系的添加em.persist(new Student("小張"));em.persist(new Teacher("李老師"));} //JPA多對多測試類:建立學生跟老師的聯系@Overridepublic void jpaTest() {//建立學生和老師的關系Student student=em.find(Student.class, 15);student.addTeacher(em.getReference(Teacher.class, 16));} //JPA多對多測試類:刪除學生跟老師的聯系@Overridepublic void jpaTest() {//刪除學生跟老師的聯系Student student=em.find(Student.class, 15);student.removeTeacher(em.getReference(Teacher.class, 16));} //JPA多對多測試類:刪除對象:只刪除教師//直接不接觸外鍵,直接刪除老師,這種方式刪除不了,被維護端沒有權限刪除外鍵,拋異常@Overridepublic void jpaTest() {em.remove(em.getReference(Teacher.class, 16));} //JPA多對多測試類:刪除對象:只刪除教師//先解除學生與老師的關系,再刪除教師對象@Overridepublic void jpaTest() {Student student=em.find(Student.class, 15);Teacher teacher=em.getReference(Teacher.class, 16);student.removeTeacher(teacher);em.remove(teacher);} //JPA多對多測試類:刪除對象:學生,并刪除第三表中的記錄,不刪除老師//關系維護端有權限刪除外鍵@Overridepublic void jpaTest() {em.remove(em.getReference(Student.class, 15));}?
?
四、聯合主鍵:
以飛機航線為例:兩個城市決定一條航線。
1、聯合主鍵的三個要求:
(1)必須定義無參構造函數;
(2)必須實現序列化接口Serializable;
(3)必須重寫hashCode()和equals()方法。
2、AirLinkPK聯合主鍵類:
/*聯合主鍵的三個要求: 1.必須定義無參構造函數 2.必須實現序列化接口Serializable 3.必須重寫hashCode()和equals()方法 */ @Embeddable public class AirLinePK implements Serializable { public AirLinePK(){}public AirLinePK(String startCity, String endCity) {this.startCity = startCity;this.endCity = endCity;}private String startCity;//開始城市private String endCity;//結束城市@Column(length=3)public String getStartCity() {return startCity;}public void setStartCity(String startCity) {this.startCity = startCity;}@Column(length=3)public String getEndCity() {return endCity;}public void setEndCity(String endCity) {this.endCity = endCity;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((endCity == null) ? 0 : endCity.hashCode());result = prime * result + ((startCity == null) ? 0 : startCity.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;AirLinePK other = (AirLinePK) obj;if (endCity == null) {if (other.endCity != null)return false;} else if (!endCity.equals(other.endCity))return false;if (startCity == null) {if (other.startCity != null)return false;} else if (!startCity.equals(other.startCity))return false;return true;} }3、AirLine類:
@Entity public class AirLine {public AirLine(){}public AirLine(AirLinePK id) {this.id = id;}public AirLine(String startCity,String endCity,String name){this.id=new AirLinePK(startCity,endCity);this.name=name;}private AirLinePK id;private String name;//聯合主鍵的實體標識符@EmbeddedIdpublic AirLinePK getId() {return id;}public void setId(AirLinePK id) {this.id = id;}@Column(length=20)public String getName() {return name;}public void setName(String name) {this.name = name;} }3、聯合主鍵測試類:
//聯合主鍵測試類@Overridepublic void jpaTest() {em.persist(new AirLine("PEK","SHA","北京飛上海"));}?
?
總結
以上是生活随笔為你收集整理的JPA规范:一对多、一对一、多对多的双向关联与级联操作以及JPA联合主键的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring使用JPA进行Dao层的数据
- 下一篇: SpringBoot简介、SpringB