1. 程式人生 > >Hibernate持久層框架使用【五】hibernate表關聯

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);