日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

hibernate 一对一(One-to-One)

發(fā)布時間:2025/6/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hibernate 一对一(One-to-One) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一對一(one-to-one)實(shí)例(Person-IdCard)

一對一的關(guān)系在數(shù)據(jù)庫中表示為主外關(guān)系.例如.人和身份證的關(guān)系.每個人都對應(yīng)一個身份證號.我們應(yīng)該兩個表.一個是關(guān)于人信息的表(Person).別外一個是身份證相關(guān)信息的表(id_card).id_card表的主鍵對應(yīng)該P(yáng)erson表的主鍵id,也是Person表的外鍵.有人才能有身份證.所以此例中Person是主表,id_card表為從表。

hibernate的一對一關(guān)系有兩種形式,一種是共享主鍵方式,另一種是唯一外鍵方式.

一、共享主鍵方式實(shí)現(xiàn)一對一

1. 實(shí)體類設(shè)計(jì)如下:

Person類:

Java代碼 ?
  • package?com.reiyen.hibernate.domain;??
  • ??
  • public?class?Person?{??
  • ??
  • ????private?int?id;??
  • ????private?String?name;??
  • ????private?IdCard?idCard;??
  • ??
  • ???????//setter和getter方法??
  • }??
  • ?IdCard類:

    Java代碼 ?
  • package?com.reiyen.hibernate.domain;??
  • ??
  • public?class?IdCard?{??
  • ??
  • ????private?int?id;??
  • ????private?Date?authorizeDate;??
  • ????private?Person?person;??
  • ?????????
  • ???????//setter和getter方法??
  • }??
  • ?2.映射文件:

    Person.hbm.xml文件如下:

    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?package="com.reiyen.hibernate.domain">??
  • ????<class?name="Person"?>??
  • ????????<id?name="id"?>??
  • ????????????<generator?class="native"?/>??
  • ????????</id>??
  • ????????<property?name="name"?/>??
  • ????????<one-to-one?name="idCard"?/>??
  • ????</class>??
  • </hibernate-mapping>??
  • ?IdCard.hbm.xml文件如下:

    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?package="com.reiyen.hibernate.domain">??
  • ????<class?name="IdCard"?table="id_card">??
  • ????????<id?name="id">??
  • ????????????<!--?id_card的主鍵來源person,也就是共享idCard的主鍵?-->??
  • ????????????<generator?class="foreign">??
  • ????????????????<param?name="property">person</param>??
  • ????????????</generator>??
  • ????????</id>??
  • ????????<property?name="authorizeDate"?column="authorize_date"?/>??
  • ????????<!--?one-to-one標(biāo)簽的含義,指示hibernate怎么加載它的關(guān)聯(lián)對象,默認(rèn)根據(jù)主鍵加載,???
  • ????????????constrained="true",?表明當(dāng)前主鍵上存在一個約束,id_card的主鍵作為外鍵參照了person?-->??
  • ????????<one-to-one?name="person"?constrained="true"></one-to-one>??
  • ????</class>??
  • </hibernate-mapping>??
  • 3. 在hibernate.cfg.xml文件中注冊映射文件:

    Xml代碼 ?
  • <mapping?resource="com/reiyen/hibernate/domain/Person.hbm.xml"?/>??
  • <mapping?resource="com/reiyen/hibernate/domain/IdCard.hbm.xml"?/>??
  • ?4.測試類如下:

    Java代碼 ?
  • public?class?One2One?{??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Person?person?=?add();??
  • ????????System.out.println("peron?name:"?+?person.getName());??
  • ????}??
  • ??????
  • ????static?Person?add(){??
  • ????????Session?session?=?null;??
  • ????????Transaction?tran?=?null;??
  • ????????try?{??
  • ????????????session?=?HibernateUtil.getSession();??
  • ????????????IdCard?idCard?=?new?IdCard();??
  • ????????????idCard.setAuthorizeDate(new?Date());??
  • ??
  • ????????????Person?p?=?new?Person();??
  • ????????????p.setName("person1");??
  • ?????????????p.setIdCard(idCard);???//?1??
  • ????????????idCard.setPerson(p);???//?2??
  • ????????????tran?=?session.beginTransaction();??
  • ????????????session.save(p);??
  • ????????????session.save(idCard);????
  • ????????????tran.commit();??
  • ????????????return?p;??
  • ????????}?finally?{??
  • ????????????if?(session?!=?null)??
  • ????????????????session.close();??
  • ????????}??
  • ?控制臺打印信息如下所示:

    Hibernate: insert into Person (name) values (?)
    Hibernate: insert into id_card (authorize_date, id) values (?, ?)
    person name : person1

    ?

    數(shù)據(jù)庫表id_card的創(chuàng)建語句如下所示:(重點(diǎn)注意紅色字體部分)

    DROP TABLE IF EXISTS `test`.`id_card`;
    CREATE TABLE? `test`.`id_card` (
    ? `id` int(11) NOT NULL,
    ? `authorize_date` datetime DEFAULT NULL,
    ? PRIMARY KEY (`id`),
    ? KEY `FK627C1FB4284AAF67` (`id`),
    ? CONSTRAINT `FK627C1FB4284AAF67` FOREIGN KEY (`id`) REFERENCES `person` (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    數(shù)據(jù)庫中記錄如下所示:
    mysql> select * from person;
    +----+---------+
    | id | name??? |
    +----+---------+
    |? 1 | person1 |
    +----+---------+
    1 row in set (0.00 sec)

    mysql> select * from id_card;
    +----+---------------------+
    | id | authorize_date????? |
    +----+---------------------+
    |? 1 | 2010-03-23 01:07:25 |
    +----+---------------------+
    1 row in set (0.00 sec)

    ?

    在測試時一定要注意寫上這句代碼:

    Java代碼 ?
  • idCard.setPerson(p);???
  • 這是讓從對象關(guān)聯(lián)上它所從屬的主對象。如果沒有這句話,則會拋出如下異常:

    org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property: person

    ?

    5. 查詢測試,測試類如下:

    Java代碼 ?
  • public?class?One2One?{??
  • ????public?static?void?main(String[]?args)?{??
  • ????????query(1);??
  • ????}??
  • ??????
  • ????static?void?query(Integer?id){??
  • ????????Session?session?=?null;??
  • ????????try?{??
  • ????????????session?=?HibernateUtil.getSession();??
  • ????????????Person?person?=?(Person)session.get(Person.class,?id);//4??
  • ???????????????????????System.out.println(person.getIdCard().getAuthorizeDate());//3??
  • ????????????????????????//IdCard?idCard?=?(IdCard)session.get(IdCard.class,?id);?//1??
  • ????????????//System.out.println(idCard.getPerson().getName());??????//2??
  • ????????}?finally?{??
  • ????????????if?(session?!=?null)??
  • ????????????????session.close();??
  • ????????}??
  • ????}??
  • }??
  • ?執(zhí)行此測試類時,控制臺打印信息如下所示:

    Hibernate: select person0_.id as id3_1_, person0_.name as name3_1_, idcard1_.id as id4_0_, idcard1_.authorize_date as authorize2_4_0_ from Person person0_ left outer join id_card idcard1_ on person0_.id=idcard1_.id where person0_.id=?
    2010-03-23 21:46:07.0

    從打印的SQL語句可以看出,一對一關(guān)系查詢主對象時,然后得到主對象中的從屬對象,通過left join一次就把查詢結(jié)果查詢出來了,因?yàn)閺膶ο髲膶儆谥鲗ο蟆6粚Χ?#xff0c;多對一關(guān)系時,從打印的SQL語句可知,它經(jīng)過了兩次查詢才將查詢結(jié)果查詢出來。這是它們的區(qū)別。如果一對一關(guān)系中先查詢從屬對象,然后得到從屬中的主對象時(即把上面測試類中的注釋1, 2都去掉再運(yùn)行),控制臺打印信息如下:

    Hibernate: select idcard0_.id as id4_0_, idcard0_.authorize_date as authorize2_4_0_ from id_card idcard0_ where idcard0_.id=?
    Hibernate: select person0_.id as id3_1_, person0_.name as name3_1_, idcard1_.id as id4_0_, idcard1_.authorize_date as authorize2_4_0_ from Person person0_ left outer join id_card idcard1_ on person0_.id=idcard1_.id where person0_.id=?
    person1

    從打印的SQL可以看出,這種先查從對象,然后得到從屬對象中的主對象,要經(jīng)過兩次查詢才能得到查詢結(jié)果。

    如果只把測試程序中注釋1去掉運(yùn)行,則只會執(zhí)行上面兩次查詢中的第一次查詢。

    6.one-to-one(元素)懶加載分析:

    必須同時滿足下面的三個條件時才能實(shí)現(xiàn)懶散加載:1).lazy!=false (lazy缺省方式就!=false)2).constrained=true 3).fetch=select(fetch缺省方式即為select)
    (因?yàn)橹鞅聿荒苡衏onstrained=true,所以主表沒有懶加載功能)。能夠懶加載的對象都是被改寫過的代理對象,當(dāng)相關(guān)聯(lián)的session沒有關(guān)閉時,訪問這些懶加載對象(代理對象)的屬性(getId和getClass除外)時,hibernate會初始化這些代理,或用Hibernate.initialize(proxy)來初始化代理對象;當(dāng)相關(guān)聯(lián)的session關(guān)閉后,再訪問懶加載的對象將會出現(xiàn)異常。

    測試:(1).注釋掉查詢測試程序中標(biāo)記為3的語句,運(yùn)行程序,控制臺打印信息如下:

    Hibernate: select person0_.id as id4_1_, person0_.name as name4_1_, idcard1_.id as id5_0_, idcard1_.authorize_date as authorize2_5_0_ from Person person0_ left outer join id_card idcard1_ on person0_.id=idcard1_.id where person0_.id=?

    說明查詢主對象Person時沒有懶加載特性,因此它通過left outer join id_card表,同時把它的從對象IdCard也查詢出來了。那為什么一對一中查詢主對象時,不能實(shí)現(xiàn)懶加載呢??大家可以看看person表的結(jié)構(gòu),你從表結(jié)構(gòu)中根本不能決斷出Person對象有沒有相應(yīng)的IdCard對象,所以它無法給setIdCard賦值(hibernate不能想當(dāng)然的認(rèn)為你有值,給你new一個代理對象給它),所以它一定要去查詢相關(guān)聯(lián)的對象表,看是否有與此Person對應(yīng)的IdCard記錄。而如果查詢的是從對象IdCard時,因?yàn)閕dcard中的id是一個person表的一個外鍵,所以它必定有一個相對應(yīng)的Person對象(因?yàn)橛衏onstrained=true),所以它可以先返回給你一個代理對象,當(dāng)你真正需要Person對象的數(shù)據(jù)時,它再去查詢數(shù)據(jù)庫。

    (2).注釋掉查詢測試程序中標(biāo)記為3,4的語句,同進(jìn)將標(biāo)記為1的語句前的注釋去掉再運(yùn)行程序,控制臺打印信息如下:

    Hibernate: select idcard0_.id as id5_0_, idcard0_.authorize_date as authorize2_5_0_ from id_card idcard0_ where idcard0_.id=?

    從打印信息可以看出,查詢從對象IdCard時實(shí)現(xiàn)了懶加載功能,因?yàn)樗徊樵兞薎dCard對象,而關(guān)聯(lián)的Person對象它沒有進(jìn)行查詢。

    (3).如果在(2)基礎(chǔ)上將標(biāo)記為2的語句前的注釋也去掉再運(yùn)行程序,控制臺打印信息如下:

    Hibernate: select idcard0_.id as id5_0_, idcard0_.authorize_date as authorize2_5_0_ from id_card idcard0_ where idcard0_.id=?
    Hibernate: select person0_.id as id4_1_, person0_.name as name4_1_, idcard1_.id as id5_0_, idcard1_.authorize_date as authorize2_5_0_ from Person person0_ left outer join id_card idcard1_ on person0_.id=idcard1_.id where person0_.id=?
    person1

    它就進(jìn)行了兩次查詢,將IdCard關(guān)聯(lián)的Person對象也進(jìn)行了查詢。因?yàn)樵L問這些懶加載對象(代理對象)的屬性(getId和getClass除外)時,hibernate會初始化這些代理.

    (4).如果修改IdCard.hbm.xml映射文件,增加fetch="join",如下所示:

    Xml代碼 ?
  • <one-to-one?name="person"?constrained="true"?fetch="join"/>??
  • 再按(2)進(jìn)行測試,此時控制臺打印信息如下:

    Hibernate: select idcard0_.id as id5_1_, idcard0_.authorize_date as authorize2_5_1_, person1_.id as id4_0_, person1_.name as name4_0_ from id_card idcard0_ inner join Person person1_ on idcard0_.id=person1_.id where idcard0_.id=?
    此時查詢從對象IdCard時也不再懶加載了,通過inner join一次性將主從對象都查詢出來。

    (5).如果修改IdCard.hbm.xml映射文件,增加lazy="false",如下所示:

    Xml代碼 ?
  • <one-to-one?name="person"?constrained="true"?lazy="false"?/>??
  • 再按(2)進(jìn)行測試,此時控制臺打印信息如下:

    Hibernate: select idcard0_.id as id5_0_, idcard0_.authorize_date as authorize2_5_0_ from id_card idcard0_ where idcard0_.id=?
    Hibernate: select person0_.id as id4_1_, person0_.name as name4_1_, idcard1_.id as id5_0_, idcard1_.authorize_date as authorize2_5_0_ from Person person0_ left outer join id_card idcard1_ on person0_.id=idcard1_.id where person0_.id=?
    雖然也不實(shí)現(xiàn)懶加載功能,一次性將主從對象都查詢出來,但此時是經(jīng)過兩次查詢才得到結(jié)果。

    如果修改IdCard.hbm.xml映射文件,增加lazy="proxy",如下所示,與缺省時一樣的效果,因?yàn)槿笔r,lazy是=proxy

    Xml代碼 ?
  • <one-to-one?name="person"?constrained="true"?lazy="proxy"?/>??
  • 如果修改IdCard.hbm.xml映射文件,如下所示,則lazy(懶加載失效),此時效果如測試(4)。

    Xml代碼 ?
  • <one-to-one?name="person"?constrained="true"?lazy="proxy"?fetch="join"/>??
  • ?

    二、唯一外鍵方式實(shí)現(xiàn)一對一

    基于外鍵的one-to-one可以描述為多對一。

    ?hibernate一對一唯一外鍵關(guān)聯(lián)映射(雙向關(guān)聯(lián)Person<---->IdCard)
    一對一唯一外鍵雙向關(guān)聯(lián),需要在另一端(person),添加<one-to-one>標(biāo)簽,指示hibernate如何加載
    其關(guān)聯(lián)對象,默認(rèn)根據(jù)主鍵加載idcard,外鍵關(guān)聯(lián)映射中,因?yàn)閮蓚€實(shí)體采用的是idcard的外鍵維護(hù)的關(guān)系, 所以不能指定主鍵加載idcard,而要根據(jù)idcard的外鍵加載,所以采用如下映射方式:
    <one-to-one name="idcard" property-ref="person"/>

    IdCard.hbm.xml的映射文件如下:

    ?

    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?package="com.itcast.hibernate.domain">??
  • ????<class?name="IdCard"?table="id_card">??
  • ????????<id?name="id">??
  • ????????????<generator?class="native"?/>??
  • ????????</id>??
  • ????????<property?name="authorizeDate"?column="authorize_date"?/>??
  • <!--?指定多的一端的unique=true,這樣就限制了多的一端的多重性為一???
  • ????????????通過這種手段映射一對一唯一外鍵關(guān)聯(lián)?-->??
  • ????????<many-to-one?name="person"?column="person_id"?unique="true"?/>??
  • ????</class>??
  • </hibernate-mapping>??
  • ?Person.hbm.xml的映射文件如下:

    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?package="com.itcast.hibernate.domain">??
  • ????<class?name="Person"?>??
  • ????????<id?name="id"?>??
  • ????????????<generator?class="native"?/>??
  • ????????</id>??
  • ????????<property?name="name"?/>??
  • ????????<!--?沒有下面的one-to-one標(biāo)簽也行,但那樣就變成了單向關(guān)聯(lián)(IdCard?----》?Person)?,也就是當(dāng)知道IdCard后,能找到它屬于的對應(yīng)的人,但知道某人后,卻無法找到相對應(yīng)的IdCard-->??
  • ????????<one-to-one?name="idCard"?property-ref="person"/>??
  • ????</class>??
  • </hibernate-mapping>??
  • ?實(shí)體類不用修改,還是用上面的測試類進(jìn)行測試即可。

    保存測試類運(yùn)行后,相對共享主鍵方式的one-to-one,id_card表的結(jié)構(gòu)發(fā)生了變化,表結(jié)構(gòu)如下所示:

    DROP TABLE IF EXISTS `test`.`id_card`;
    CREATE TABLE? `test`.`id_card` (
    ? `id` int(11) NOT NULL AUTO_INCREMENT,
    ? `authorize_date` datetime DEFAULT NULL,
    ? `person_id` int(11) DEFAULT NULL,
    ? PRIMARY KEY (`id`),
    ? UNIQUE KEY `person_id` (`person_id`),
    ? KEY `FK627C1FB45B253C91` (`person_id`),
    ? CONSTRAINT `FK627C1FB45B253C91` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

    數(shù)據(jù)庫表中記錄如下:

    mysql> select * from person;
    +----+---------+
    | id | name??? |
    +----+---------+
    |? 1 | person1 |
    +----+---------+
    1 row in set (0.00 sec)

    mysql> select * from id_card;
    +----+---------------------+-----------+
    | id | authorize_date????? | person_id |
    +----+---------------------+-----------+
    |? 1 | 2010-03-23 22:40:38 |???????? 1 |
    +----+---------------------+-----------+
    1 row in set (0.00 sec)

    ?

    如果Person.hbm.xml映射文件中沒有<one-to-one/>這一項(xiàng)的話,運(yùn)行測試:

    Java代碼 ?
  • Person?person?=?(Person)session.get(Person.class,?id);??
  • System.out.println(person.getIdCard().getAuthorizeDate());??
  • ?會拋出如下異常:

    ?java.lang.NullPointerException

    因?yàn)檫@種關(guān)系成了IdCard--->Person的單向關(guān)聯(lián)了。知道了Person,找不到對應(yīng)的IdCard.

    當(dāng)運(yùn)行如下測試時:

    Java代碼 ?
  • Person?person?=?(Person)session.get(Person.class,?id);??
  • System.out.println(person.getIdCard());??
  • ?控制臺會打印出Person相對應(yīng)的IdCard為null.

    ?

    但如果得到了IdCard,卻能找到相應(yīng)的Person.測試如下:

    Java代碼 ?
  • IdCard?idCard?=?(IdCard)session.get(IdCard.class,?id);??
  • System.out.println(idCard.getPerson().getName());??
  • ?能得到正常的結(jié)果,person name為person1.

    總結(jié): 在缺省情況下,hibernate只有在一對一關(guān)聯(lián)中,查詢主對象時,是進(jìn)行關(guān)聯(lián)查詢一次得到查詢結(jié)果,其它(多對多、多對一、一對多、一對一查詢從對象)的查詢都是分兩次查詢得到查詢結(jié)果。

    總結(jié)

    以上是生活随笔為你收集整理的hibernate 一对一(One-to-One)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。