一對一關(guān)系分以下幾種:
- 單向主鍵一對一
- 雙向主鍵一對一
- 單向外鍵一對一
- 雙向外鍵一對一
在此先介紹統(tǒng)一用的實體類:
package entity;
import java.util.Date;
/**
* 單向one to one溯香,User指向Group
* 主鍵關(guān)聯(lián)
* @author arkulo
*
*/
public class User {
private int id;
private String userName;
private String passWd;
private Date addtime;
private IdCard ic;
public IdCard getIc() {
return ic;
}
public void setIc(IdCard ic) {
this.ic = ic;
}
public Date getAddtime() {
return addtime;
}
public void setAddtime(Date addtime) {
this.addtime = addtime;
}
public User(){}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWd() {
return passWd;
}
public void setPassWd(String passWd) {
this.passWd = passWd;
}
}
package entity;
/**
* 身份證,不需要指向User
* @author arkulo
*
*/
public class IdCard {
private int id;
private String idCard;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
}
一、單向主鍵一對一
User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.User" >
<id name="id">
<!-- 單向主鍵關(guān)聯(lián)惫企,class應(yīng)該設(shè)置成foreign -->
<generator class="foreign">
<!-- User類中的ic這個屬性 -->
<param name="property">ic</param>
</generator>
</id>
<property name="userName" />
<property name="passWd" />
<property name="addtime" type="time" />
<!-- constrained表示一個外鍵約束议薪,默認為false,true的時候數(shù)據(jù)庫表會加外鍵 -->
<one-to-one name="ic" constrained="true" cascade="delete"></one-to-one>
</class>
</hibernate-mapping>
idcard.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.IdCard" >
<id name="id">
<generator class="native" />
</id>
<property name="idCard" />
</class>
</hibernate-mapping>
單元測試:
package entity;
import java.util.Date;
import org.hibernate.classic.Session;
import junit.framework.TestCase;
import util.hibernateUtil;
/**
* 一對一關(guān)聯(lián)分為兩大類:主鍵關(guān)聯(lián)县匠,唯一外鍵關(guān)聯(lián)
* 一對一關(guān)聯(lián)還有方向之分:單向和雙向
*
* 本項目是一對一單向主鍵關(guān)聯(lián)方式
*
* @author arkulo
*
*/
public class TestOneToOne extends TestCase {
/**
* 單向主鍵one to one风科,添加數(shù)據(jù),注意主鍵是否需要提前生成
* 因為是一對一乞旦,主鍵外鍵關(guān)聯(lián)是做在user表上的贼穆,因此,要測試是否提前生成idcard的主鍵
*/
public void test1() {
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
IdCard idcard = new IdCard();
idcard.setIdCard("123456789");
// 這里不用saveidcard兰粉,user保存的時候會一起save
User user = new User();
user.setUserName("王蕊");
user.setPassWd("123456");
user.setAddtime(new Date());
user.setIc(idcard);
session.save(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
hibernateUtil.closeSession(session);
}
// 讀取關(guān)聯(lián)數(shù)據(jù)故痊,get函數(shù)能不能在讀取User的時候,把idCard也讀取出來玖姑,用不同的session愕秫,避免一級緩存
try {
session = hibernateUtil.getSession();
session.beginTransaction();
User user = (User) session.get(User.class, 1);
System.out.println("用戶名:" + user.getUserName());
// 上面user的查詢是直接發(fā)出一條sql語句,但是并沒有關(guān)聯(lián)查詢idcard焰络,當執(zhí)行到下面這句話的時候戴甩,因為可以從user中
// 獲得idcard的主鍵id,因此又發(fā)出了一條sql闪彼,條件是id的去查詢idcard
System.out.println("身份證:" + user.getIc().getIdCard());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
hibernateUtil.closeSession(session);
}
}
/**
* 如果要刪除idcard數(shù)據(jù)甜孤,user數(shù)據(jù)會怎么樣?
* 請先用test1函數(shù)做數(shù)據(jù)初始化,初始化后運行此函數(shù)缴川,請將hibernate.hbm2ddl.auto改為update
*/
public void test2() {
// 在這里調(diào)用一下初始化數(shù)據(jù)的test1函數(shù)
test1();
System.out.println("----------------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 因為有外鍵約束存在茉稠,如果構(gòu)造直接構(gòu)造一個瞬時狀態(tài)的IdCard對象,然后直接去刪除二跋,系統(tǒng)會報錯战惊,提示
// 有外鍵約束,不能刪除
// IdCard ic = new IdCard();
// ic.setId(1);
// session.delete(ic);
// 這里我們模擬構(gòu)造一個順勢狀態(tài)的User扎即,看是否能夠直接刪除
// 這里沒有構(gòu)造idcard對象吞获,單獨刪除user成功,idcard記錄沒有刪除
// User user = new User();
// user.setId(1);
// session.delete(user);
// 這里我們再來試一下谚鄙,構(gòu)造了idcard各拷,看能不能關(guān)聯(lián)刪除
// 這里也沒有刪除idcard
// IdCard ic = new IdCard();
// ic.setId(1);
//
// User user = new User();
// user.setId(1);
// user.setIc(ic);
// session.delete(user);
// 這里我們設(shè)置一下映射文件中的級聯(lián)方式,讓他的級聯(lián)方式變成delete闷营,看看能不能刪除idcard
// 只有user擁有了id烤黍,idcard也擁有了id,加上級聯(lián)關(guān)系傻盟,然后刪除user的時候速蕊,才會連鎖刪除idcard
IdCard ic = new IdCard();
ic.setId(1);
User user = new User();
user.setId(1);
user.setIc(ic);
session.delete(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
hibernateUtil.closeSession(session);
}
}
}
二、雙向主鍵一對一
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.User" >
<id name="id">
<!-- 單向主鍵關(guān)聯(lián)娘赴,class應(yīng)該設(shè)置成foreign -->
<generator class="foreign">
<!-- User類中的ic這個屬性 -->
<param name="property">ic</param>
</generator>
</id>
<property name="userName" />
<property name="passWd" />
<property name="addtime" type="time" />
<!-- constrained表示一個外鍵約束规哲,默認為false -->
<one-to-one name="ic" constrained="true" cascade="delete"></one-to-one>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.IdCard" >
<id name="id">
<generator class="native" />
</id>
<property name="idCard" />
<!-- 這里不需要設(shè)置constrained屬性?給idcard也加上這個屬性诽表,在數(shù)據(jù)庫中就生成了由idcard表到user表的外鍵約束-->
<!-- 不能在一對一關(guān)系中唉锌,兩邊都加上constrained屬性,會報錯的 -->
<!-- 就是今天竿奏,就是今天袄简,我有了人生第一個機械鍵盤,爽的不行不行的泛啸! -->
<one-to-one name="user"></one-to-one>
</class>
</hibernate-mapping>
單元測試:
package entity;
import java.util.Date;
import org.hibernate.classic.Session;
import junit.framework.TestCase;
import util.hibernateUtil;
/**
* 一對一關(guān)聯(lián)分為兩大類:主鍵關(guān)聯(lián)绿语,唯一外鍵關(guān)聯(lián)
* 一對一關(guān)聯(lián)還有方向之分:單向和雙向
*
* 本項目是雙向主鍵一對一關(guān)聯(lián),測試目的如下:
* 1. 雙向關(guān)聯(lián)插入平痰?如果是在idcard中添加user對象汞舱,是不是保存idcard對象,就算是保存了user對象
* 2. 不管是讀取那個對象的數(shù)據(jù)宗雇,都會帶出關(guān)聯(lián)的數(shù)據(jù)昂芜,不需要單獨去查詢
* 3. 刪除,是否可以反向刪除赔蒲,例如刪除idcard泌神,然后會不會也刪除user
* @author arkulo
*
*/
public class TestOneToOne extends TestCase {
// 1. 雙向數(shù)據(jù)插入的測試
public void test1() {
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
IdCard ic = new IdCard();
ic.setIdCard("123456789");
User user = new User();
user.setUserName("王蕊");
user.setAddtime(new Date());
user.setPassWd("123323");
user.setIc(ic);
ic.setUser(user);
// 單獨保存idcard不會級聯(lián)保存user數(shù)據(jù)良漱,只會單獨保存idcard的數(shù)據(jù)
// session.save(ic);
// 如果單獨保存user對象,會連天idcard對象一起保存
session.save(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
hibernateUtil.closeSession(session);
}
}
/**
* 2. 讀取數(shù)據(jù),由user是否能關(guān)聯(lián)查處
*/
public void test2() {
// 這里需要調(diào)用一下數(shù)據(jù)初始化函數(shù)test
test1();
System.out.println("-----------------------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 從user角度讀取數(shù)據(jù)欢际,先發(fā)出一條sql語句母市,查詢user,然后打印username损趋,查詢idcard的sql語句這時候并沒有發(fā)出
User user = (User) session.get(User.class, 1);
System.out.println("用戶名:" + user.getUserName());
// 在這里要用到idcard的數(shù)據(jù)的時候患久,才發(fā)出了查詢idcard的sql語句(left out join)
System.out.println("身份證號碼:" + user.getIc().getIdCard());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
hibernateUtil.closeSession(session);
}
// 這里通過查詢idcard,看能不能級聯(lián)查處user數(shù)據(jù)浑槽,在不同的session里面測試蒋失,避免一級緩存
try {
session = hibernateUtil.getSession();
session.beginTransaction();
IdCard ic = (IdCard) session.get(IdCard.class, 1);
// 這種情況下,一次性采用連表查詢left out join將兩張表一起取出來了
System.out.println("用戶名:" + ic.getUser().getUserName());
System.out.println("身份證編號:" + ic.getIdCard());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
hibernateUtil.closeSession(session);
}
}
/**
* 3. 刪除的時候會不會有級聯(lián)效果
*/
public void test3() {
test1();
System.out.println("-----------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 構(gòu)造一個user瞬時對象桐玻,然后直接刪除
IdCard ic = new IdCard();
ic.setId(1);
User user = new User();
user.setId(1);
user.setIc(ic);
ic.setUser(user);
// 如果單獨刪除user篙挽,系統(tǒng)會自動級聯(lián)刪除idcard
session.delete(user);
// 如果單獨刪除idcard,系統(tǒng)報錯镊靴,提示有外鍵約束铣卡,不能刪除
// session.delete(ic);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
hibernateUtil.closeSession(session);
}
}
}
三、單向外鍵一對一
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.User" >
<id name="id">
<generator class="native" />
</id>
<property name="userName" />
<property name="passWd" />
<property name="addtime" type="time" />
<!-- 單向一對一外鍵關(guān)聯(lián)偏竟,其實就是多對一關(guān)聯(lián)設(shè)置為唯一 -->
<many-to-one name="ic" unique="true" cascade="delete"></many-to-one>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.IdCard" >
<id name="id">
<generator class="native" />
</id>
<property name="idCard" />
</class>
</hibernate-mapping>
單元測試:
package entity;
import java.util.Date;
import org.hibernate.classic.Session;
import junit.framework.TestCase;
import util.hibernateUtil;
/**
* 單向外鍵一對一關(guān)聯(lián)
*
* 1. 添加數(shù)據(jù)煮落,級聯(lián)保存,保存user的時候踊谋,是否能同時保存idcard
* 2. 查詢數(shù)據(jù)州邢,查詢user的時候,是否能查處idcard
* 3. 刪除數(shù)據(jù)褪子,刪除user,是否能級聯(lián)刪除idcard骗村,如果把級聯(lián)規(guī)則改掉嫌褪,刪除user,是否可以不刪除idcard
* @author arkulo
*
*/
public class TestOneToOne extends TestCase {
// 添加數(shù)據(jù)
public void test1()
{
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 外間單向關(guān)聯(lián)胚股,首先需要保存idcard笼痛,如果只是保存user的時候,會提示錯誤琅拌,user中的外間關(guān)聯(lián)字段會沒有值
// 也就是說缨伊,單獨保存user的時候,不能一并保存idcard對象
IdCard ic = new IdCard();
ic.setIdCard("1234567");
session.save(ic);
User user = new User();
user.setUserName("王蕊");
user.setAddtime(new Date());
user.setIc(ic);
session.save(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
// 查詢數(shù)據(jù)进宝,是否能實現(xiàn)查詢user的時候刻坊,一次性關(guān)聯(lián)查詢出idcard
public void test2()
{
// 初始化數(shù)據(jù)
test1();
System.out.println("-------------------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 采用load查詢方式
User user = (User)session.load(User.class, 1);
// 這里單獨的發(fā)出一條sql語句,去查詢user表党晋,并沒有查詢idcard
System.out.println("用戶名:"+user.getUserName());
// 這里單獨的發(fā)出了一條sql語句谭胚,where條件是id徐块,去查詢idcard
System.out.println("身份證編號:"+user.getIc().getIdCard());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
// 刪除操作
public void test3()
{
test1();
System.out.println("-----------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 自定義一個idcard瞬時對象
IdCard ic = new IdCard();
ic.setId(1);
// 自定義一個順勢對象user
User user = new User();
user.setId(1);
user.setIc(ic);
// 在cascade默認情況下,單獨刪除user灾而,不會級聯(lián)刪除idcard的:亍!
// 在cascade設(shè)為delete情況下旁趟,單獨刪除user昼激, 會級聯(lián)刪除idcard
session.delete(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
}
四、雙向外鍵一對一
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.User" >
<id name="id">
<generator class="native" />
</id>
<property name="userName" />
<property name="passWd" />
<property name="addtime" type="time" />
<!-- 單向一對一外鍵關(guān)聯(lián)锡搜,其實就是多對一關(guān)聯(lián)設(shè)置為唯一 -->
<many-to-one name="ic" unique="true" cascade="delete"></many-to-one>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.IdCard" >
<id name="id">
<generator class="native" />
</id>
<property name="idCard" />
<!--
先拋出問題:
one to one默認是兩個對象的主鍵進行關(guān)聯(lián)橙困,而我們現(xiàn)在是要用外鍵關(guān)聯(lián),也就是說User的一個屬性(非主鍵)要和idcard進行關(guān)聯(lián)余爆,
這個如何設(shè)置纷宇?
解決辦法:
property-ref這個選項可以設(shè)定User對象中哪個屬性和idcard表的主鍵進行關(guān)聯(lián),實際代碼中指定是user對象的ic屬性蛾方。
-->
<one-to-one name="user" property-ref="ic"></one-to-one>
</class>
</hibernate-mapping>
單元測試:
package entity;
import java.util.Date;
import org.hibernate.classic.Session;
import junit.framework.TestCase;
import util.hibernateUtil;
/**
* 雙向一對一外鍵關(guān)聯(lián)
* 1. 在設(shè)置映射的時候像捶,idcard的one to one映射加上property-ref的作用
* 2. 新增,新增之后查看idcard和user之間的關(guān)聯(lián)關(guān)系
* 3. 查詢桩砰,雙向關(guān)聯(lián)是基于對象之間的拓春,不是數(shù)據(jù)庫表之間的,數(shù)據(jù)庫表里還是user表中加字段亚隅,關(guān)聯(lián)idcard
* 4. 刪除硼莽,雙向關(guān)聯(lián),刪除idcard會刪除user嗎煮纵?
* @author arkulo
*
*/
public class TestOneToOne extends TestCase {
// 新增數(shù)據(jù)
public void test1(){
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
IdCard ic = new IdCard();
ic.setIdCard("12345678");
User user = new User();
user.setUserName("王蕊");
user.setPassWd("242424");
user.setAddtime(new Date());
user.setIc(ic);
ic.setUser(user);
// 這里我們來嘗試一下懂鸵,如果我們要保存idcard,能否一起保存use對象
// 單獨保存idcard對象行疏,只能保存idcard匆光,不會級聯(lián)保存user
// 如果在idcard的映射文件中,設(shè)置cascade屬性酿联,然后單獨保存idcard终息,系統(tǒng)會報錯
// session.save(ic);
// 單獨保存user對象也是不行的,因為這時候idcard還沒有保存贞让,沒有主鍵可以關(guān)聯(lián)
// 因此需要先保存idcard周崭,然后再保存user
session.save(ic);
session.save(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
/**
* 讀取數(shù)據(jù):
* 1. 是否能從user級聯(lián)查詢出idcard
* 2. 是否能從idcard級聯(lián)查詢出user
*/
public void test2(){
test1();
System.out.println("-------------------------------------------");
Session session = null;
// 第一種情況
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 這里也是兩條語句,在get函數(shù)的時候立即發(fā)出一條sql語句喳张,查詢user表
// 在打印身份證編號的時候發(fā)出第二條sql語句续镇,關(guān)聯(lián)查詢user表和idcard表,得出idcar的數(shù)據(jù)
User user = (User)session.get(User.class, 1);
System.out.println("用戶名:"+user.getUserName());
System.out.println("身份證編號:"+user.getIc().getIdCard());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
System.out.println("------------------------------");
// 第二種情況
try {
session = hibernateUtil.getSession();
session.beginTransaction();
// 這里一條sql語句蹲姐,把user表和idcard一起查詢出來
IdCard ic = (IdCard)session.get(IdCard.class, 1);
System.out.println("用戶名:"+ic.getUser().getUserName());
System.out.println("身份證編號:"+ic.getIdCard());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
/**
* 刪除測試
* 1. 在不設(shè)置cascade的情況下磨取,刪除user人柿,會不會級聯(lián)刪除idcard
* 2. 在設(shè)置了級聯(lián)操作下,闡述idcard忙厌,會不會刪除user
*/
public void test3(){
test1();
System.out.println("------------------------------");
Session session = null;
try {
session = hibernateUtil.getSession();
session.beginTransaction();
IdCard ic = new IdCard();
ic.setId(1);
User user = new User();
user.setId(1);
user.setIc(ic);
ic.setUser(user);
// 1. 在默認不設(shè)置cascade的情況下凫岖,刪除user是不會級聯(lián)刪除idcard的
// 2. 在默認不設(shè)置cascade的情況下,刪除idcard會報錯逢净,提示外鍵關(guān)聯(lián)哥放,不能隨意刪除
// 3. cascade設(shè)置為delete情況下,刪除user會級聯(lián)刪除idcard
// 4. cascade設(shè)置為delete情況下爹土,刪除idcard會報錯甥雕,提示外鍵關(guān)聯(lián),不能隨意刪除
session.delete(user);
// session.delete(ic);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
hibernateUtil.closeSession(session);
}
}
}