Hibernate持久層框架使用【五】hibernate表關聯
Hibernate配置表關聯的方式
一對一(OneToOne)
例如在一張表中,其中有一個列與另一個表對應,並且是唯一對應的關係時就是一對一關係了,通常我們會將這一列作為外來鍵(資料庫基礎知識),例如新建兩張表,一張company表作為公司表,一張Boss表作為老闆表,因此這裡就是一個公司對應一個老闆(公司表裡應該要有一個外來鍵列儲存老闆的id,並且是唯一的),下面使用OneToOne註解配置一下表的關聯關係
示例程式碼:
@Entity(name="company") public class Company { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; private int number; @OneToOne(fetch=FetchType.LAZY,targetEntity=Boss.class) @JoinColumn(name="C_B",unique=true,referencedColumnName="id") private Boss boss; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public Boss getBoss() { return boss; } public void setBoss(Boss boss) { this.boss = boss; } }
這是第一張表,因為要關聯Boss表,所以加入了一個Boss屬性。在@OneToOne註解中,有兩個屬性,第一個fetch表示載入的方式,FetchType.LAZY表示延遲載入,即當你獲取這張表(Company表)的資訊時,只會拿到Company表的資訊,只有在使用到Boss表的資訊時Hibernate才會根據這條資料對應的外來鍵去Boss表查詢(這麼做有助於提高效能)
還有一個註解@JoinColumn(name="C_B",unique=true,referencedColumnName="id"),即在表中加入了一個列(外來鍵列),name屬性申明列名,unique申明唯一性,referencedColumnName表示這個列對應Boss表中的id列
完成後記得在配置檔案裡配置這兩張表的對映
測試類程式碼:
OnToOne.class
public class OnToOne { public static void main(String[] args) { // TODO Auto-generated method stub MySessionFactory mySessionFactory = new MySessionFactory(); Session session = mySessionFactory.getSession(); Boss boss = new Boss(); boss.setName("馬化騰"); session.save(boss); Company company = new Company(); company.setName("Tencent"); company.setNumber(2000); company.setBoss(boss); session.save(company); mySessionFactory.commit(); mySessionFactory.close(); } }
測試程式碼中對兩張表各插入了一條資料,必須先插入Boss資料,再拿到這條資料給Company儲存,因為後面插入Company資料時還要儲存這條資料的外來鍵(Boss這條資料儲存時已經變為持久化狀態,是有id的)
執行後檢視結果,儲存成功。如果要測試它的延遲載入機制FetchType.LAZY,可以從Company表中將這條資料取出來,再取出其中的資訊(除Boss中的屬性)時,控制檯只打印了查詢Company表的sql語句,而當取出Boss中的資訊時,可以看到控制檯列印了兩條sql語句
一對多(OneToMany)
接下來是表資料一對多的關係,以班級與學生為例:
新建一個Classes類作為班級表:
@Entity(name="classes")
public class Classes {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int cid;
private String name;
@OneToMany(fetch=FetchType.LAZY,
targetEntity=Student.class,
orphanRemoval=true
cascade=CascadeType.REMOVE)
@JoinColumn(name="FKey_C_S",referencedColumnName="cid")
private Set<Student> students = new HashSet<>();
public int getCid() {
return cid;
}
public void setCid(int cid) {
this.cid = cid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
除了一些基本註解外,需要了解這裡的OneToMany註解
@OneToMany(
fetch=FetchType.LAZY, //這個屬性即前面寫過的懶載入(延遲載入)
targetEntity=Student.class, //這個屬性對應實體目標,即對應下面的學生表Student.class
orphanRemoval=true, //刪除孤兒記錄,下面會測試
cascade=CascadeType.REMOVE //級聯刪除
)
下面建立Student類作為學生表:
@Entity(name="student")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int sid;
private String name;
private int age;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
寫完後還需要在配置檔案中配置兩張表的對映
測試類程式碼示例:
public class OnToMany {
public static void main(String[] args) {
// TODO Auto-generated method stub
MySessionFactory mySessionFactory = new MySessionFactory();
Session session = mySessionFactory.getSession();
Student student1 = new Student();
student1.setName("關羽");
student1.setAge(20);
Student student2 = new Student();
student2.setName("秦瓊");
student2.setAge(21);
Classes classes1 = new Classes();
classes1.setName("一班");
classes1.getStudents().add(student1);
classes1.getStudents().add(student2);
session.save(student1);
session.save(student2);
session.save(classes1);
mySessionFactory.commit();
mySessionFactory.close();
}
}
執行儲存成功,資料表student中儲存了兩條資料,classes表中儲存了一條資料
這裡classes表中我們儲存的班級那條資料已經跟student表的兩條資料關聯了,因此可以通過查詢這條班級資料來獲得關聯它的學生資料
示例程式碼:
public class OnToMany {
public static void main(String[] args) {
// TODO Auto-generated method stub
MySessionFactory mySessionFactory = new MySessionFactory();
Session session = mySessionFactory.getSession();
//查出班級Id為1的資料
Classes classes2 = (Classes) session.get(Classes.class, 2);
System.out.println("學生個數="+classes2.getStudents().size());
mySessionFactory.commit();
mySessionFactory.close();
}
}
執行後控制檯列印顯示Set集合中有兩條資料
測試孤兒刪除,即可以通過班級來刪除它所關聯下的所有學生資料
public class OnToMany {
public static void main(String[] args) {
// TODO Auto-generated method stub
MySessionFactory mySessionFactory = new MySessionFactory();
Session session = mySessionFactory.getSession();
Classes classes1 = (Classes) session.get(Classes.class, 2);
classes1.getStudents().clear();
mySessionFactory.commit();
mySessionFactory.close();
}
}
執行後成功將資料表中關聯班級1的兩條資料刪除
測試級聯刪除,即在刪除班級1時,會同時刪除關聯了這條資料的學生資料
示例程式碼:
Classes classes1 = (Classes) session.get(Classes.class, 1);
session.delete(classes1);