版權聲明:本文為博主原創文章,如需轉載請標注轉載地址。
博客地址:http://www.cnblogs.com/caoyc/p/5602418.html
一對一關聯,可以分為兩種。一種是基於外鍵的關聯,另一種是基於主鍵的關聯。如圖
一、基於外鍵的方式
User.java
1 package com.proc.one2one; 2 3 public class User { 4 5 private Integer id; 6 private String name; 7 private IdCard card; 8 public User() { 9 } 10 public User(String name) { 11 this.name = name; 12 } 13 public Integer getId() { 14 return id; 15 } 16 public void setId(Integer id) { 17 this.id = id; 18 } 19 public String getName() { 20 return name; 21 } 22 public void setName(String name) { 23 this.name = name; 24 } 25 public IdCard getCard() { 26 return card; 27 } 28 public void setCard(IdCard card) { 29 this.card = card; 30 } 31 @Override 32 public String toString() { 33 return "User [id=" + id + ", name=" + name + "]"; 34 } 35 }
IdCard.java
1 package com.proc.one2one; 2 3 public class IdCard { 4 5 private Integer id; 6 private String cardNo; 7 private User user; 8 public IdCard(String cardNo) { 9 this.cardNo = cardNo; 10 } 11 public IdCard() { 12 } 13 public Integer getId() { 14 return id; 15 } 16 public void setId(Integer id) { 17 this.id = id; 18 } 19 public String getCardNo() { 20 return cardNo; 21 } 22 public void setCardNo(String cardNo) { 23 this.cardNo = cardNo; 24 } 25 public User getUser() { 26 return user; 27 } 28 public void setUser(User user) { 29 this.user = user; 30 } 31 @Override 32 public String toString() { 33 return "IdCard [id=" + id + ", cardNo=" + cardNo + "]"; 34 } 35 36 }
User.hbm.xml
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping package="com.proc.one2one"> 6 <class name="User" table="t_user"> 7 <id name="id" type="int" column="id" > 8 <generator class="native"></generator> 9 </id> 10 <property name="name" length="20" not-null="true"></property> 11 <one-to-one name="card" class="IdCard"></one-to-one> 12 </class> 13 </hibernate-mapping>
IdCard.hbm.xml
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping package="com.proc.one2one"> 6 <class name="IdCard" table="t_idcard"> 7 <id name="id" type="int" column="id" > 8 <generator class="native"></generator> 9 </id> 10 <property name="cardNo" type="string" column="cardNo" length="20" not-null="true"></property> 11 <many-to-one name="user" column="userid" class="User" unique="true"></many-to-one> 12 </class> 13 </hibernate-mapping>
我們可以看到一個是one-to-one一個是many-to-one的unique。
分清楚這兩個很重要,many-to-one用在保存外鍵的表,也就是說t_idcard表,one-to-one用在沒有保存外鍵的表,也就是user表.
測試代碼:
1、添加關聯關系
測試:1:
1 public class App { 2 3 private static SessionFactory factory=new Configuration() 4 .configure() 5 .addClass(User.class) 6 .addClass(IdCard.class) 7 .buildSessionFactory(); 8 9 @Test 10 public void test(){ 11 12 Session session=factory.openSession(); 13 Transaction tx=session.beginTransaction(); 14 15 User user=new User("caoyc"); 16 IdCard card=new IdCard("510123588413x"); 17 18 card.setUser(user); 19 session.save(user); 20 session.save(card); 21 tx.commit(); 22 session.close(); 23 24 } 25 }
上面我們通過IdCard來維護關聯關系,結果正確
測試2:
下面我們來試一試通過User來維護關聯關系,看結果會怎么樣?
1 @Test 2 public void test(){ 3 4 Session session=factory.openSession(); 5 Transaction tx=session.beginTransaction(); 6 7 User user=new User("caoyc"); 8 IdCard card=new IdCard("510123588413x"); 9 10 user.setCard(card); 11 12 session.save(user); 13 session.save(card); 14 tx.commit(); 15 session.close(); 16 17 }
在數據庫中我們可以看到,數據庫中表的結構完全一致,而且在t_user中也插入了數據,在t_idcard表中也同樣有數據,只不過,t_idcard表中的userid列為null,也就是說,通過user無法維護關聯關系
【總結】:在有外鍵的一方,可以維護關聯關系,而在沒有外鍵的一方無法維護關聯關系
測試3:
我們交換user對象和card對象的保存順序
1 session.save(card); 2 session.save(user);
結果數據也能夠正常插入到數據庫中,結果和測試1相同。那么交換保存順序是否有其他影響呢?答案是肯定的,雖然數據同樣插入進去了,但是在具體插入過程卻有不同。
在測試1中:我們先保存的user,通過insert into語句我們將數據正確插入,然后我們在保存card,而此時的user對象由於已經在數據庫中存在,那么必然有主鍵ID存在,我們在插入到IdCard表中,數據全部完全插入。具體sql語句
1 Hibernate: insert into t_user (name) values (?) 2 Hibernate: insert into t_idcard (cardNo, userid) values (?, ?)
在測試3中:我們先將card的數據保存到idcard表中,而此時的user的id值為null,所有在插入到idcard中是,userid會是nul
l
然后在插入user到t_user表中,那么此時user的主鍵值已經生成。為了維護關聯關系
系統會有執行一條語句
update t_idcard set cardNo=?, userid=? where id=?
所有在測試3中,我們會看到
1 Hibernate: insert into t_idcard (cardNo, userid) values (?, ?) 2 Hibernate: insert into t_user (name) values (?) 3 Hibernate: update t_idcard set cardNo=?, userid=? where id=?
【總結】:在保存數據時,我們先保存沒有外鍵的一方,然后在保存有外鍵的一方,這樣執行效率更高
2、解除關聯關系
測試1:通過User來解除關聯關系
1 @Test 2 public void test(){ 3 4 Session session=factory.openSession(); 5 Transaction tx=session.beginTransaction(); 6 7 User user=session.get(User.class, 1); 8 user.setCard(null); 9 10 tx.commit(); 11 session.close(); 12 13 }
執行的SQL語句
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_, idcard1_.id as id1_0_1_, idcard1_.cardNo as cardNo2_0_1_, idcard1_.userid as userid3_0_1_ from t_user user0_ left outer join t_idcard idcard1_ on user0_.id=idcard1_.id where user0_.id=?
可以看到,此時通過user無法來解除關聯關系
測試2:通過idcard來解除關聯關系
1 @Test 2 public void test(){ 3 4 Session session=factory.openSession(); 5 Transaction tx=session.beginTransaction(); 6 7 IdCard card=session.get(IdCard.class, 1); 8 card.setUser(null); 9 10 tx.commit(); 11 session.close(); 12 13 }
執行的SQL語句
1 Hibernate: select idcard0_.id as id1_0_0_, idcard0_.cardNo as cardNo2_0_0_, idcard0_.userid as userid3_0_0_ from t_idcard idcard0_ where idcard0_.id=? 2 Hibernate: update t_idcard set cardNo=?, userid=? where id=?
在數據庫中也可看到通過idcard的確能夠解除關聯關系
3、刪除操作
測試1:刪除user
1 @Test 2 public void test(){ 3 4 Session session=factory.openSession(); 5 Transaction tx=session.beginTransaction(); 6 7 User user=session.get(User.class, 1); 8 session.delete(user); 9 10 tx.commit(); 11 session.close(); 12 13 }
如果此時將要刪除的user數據在t_idcard表中沒有對應相應的數據,那么可以刪除成功,否則將會拋出異常,意思說有外鍵約束,該數據無法刪除
測試2:刪除idcard
1 public void test(){ 2 3 Session session=factory.openSession(); 4 Transaction tx=session.beginTransaction(); 5 IdCard card=session.get(IdCard.class, 1); 6 session.delete(card); 7 tx.commit(); 8 session.close(); 9 }
結果:刪除成功
Question:在上面測試2中,我們刪除了t_idcard中的數據,如果我需要當刪除了t_idcard中的數據后,同樣刪除t_user中對應的屬性,我們該怎么辦呢?
Answer: 那么我們需要設置cascade屬性為delete,我們在IdCard.hbm.xml
<many-to-one name="user" column="userid" class="User" unique="true" cascade="delete"></many-to-one>
也就是說,我們在刪除對象idCard是,同樣對其屬性user也做刪除動作
外鍵方式總結:
1、在有外鍵的一方,可以維護關聯關系,可以建立關聯關系,同樣也可以解除關聯關系,可以任意刪除本對象,如果在hbm.xml中設置了cascade="delete",也可以刪除關聯對象
2、在沒有外鍵的一方,不可以維護關聯關系,所有無法建立關聯關系,也無法解除關聯關系。在刪除過程中,如有沒有外鍵值對應本條數據,可以成功刪除,否則會拋出異常
二、基於主鍵的關聯方式
基於外鍵方式:一個many-to-one(有外鍵方)和一個one-to-one(無外鍵方法)
基於主鍵方式:兩個都是one-to-one
還是上面的例子,其它我們都不需要改變,我們只需要改變IdCard.hbm.xml就可以,具體代碼如下
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping package="com.proc.one2one"> 6 <class name="IdCard" table="t_idcard"> 7 <id name="id" type="int" column="id" > 8 <generator class="foreign"> 9 <param name="property">user</param> 10 </generator> 11 </id> 12 <property name="cardNo" type="string" column="cardNo" length="20" not-null="true"></property> 13 <one-to-one name="user" class="User" constrained="true"></one-to-one> 14 </class> 15 </hibernate-mapping>
代碼說明:
1、由於是基於主鍵方式,所有對應t_idcard表的主鍵id也是來自於t_user表,所有對應IdCard主鍵生成策略我們選用foregin,其中還必須指定一個從參數property,表示該主鍵生成策略基於對象的那個屬性,我們這里的屬性是user
2、constrained="true":表示給t_idcard添加一個外鍵約束,默認為false,不添加外鍵約束