日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

hibernate 一对一(One-to-One)

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

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

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

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

一、共享主鍵方式實現一對一

1. 實體類設計如下:

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標簽的含義,指示hibernate怎么加載它的關聯對象,默認根據主鍵加載,???
  • ????????????constrained="true",?表明當前主鍵上存在一個約束,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

    ?

    數據庫表id_card的創建語句如下所示:(重點注意紅色字體部分)

    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;

    數據庫中記錄如下所示:
    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);???
  • 這是讓從對象關聯上它所從屬的主對象。如果沒有這句話,則會拋出如下異常:

    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();??
  • ????????}??
  • ????}??
  • }??
  • ?執行此測試類時,控制臺打印信息如下所示:

    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語句可以看出,一對一關系查詢主對象時,然后得到主對象中的從屬對象,通過left join一次就把查詢結果查詢出來了,因為從對象從屬于主對象。而一對多,多對一關系時,從打印的SQL語句可知,它經過了兩次查詢才將查詢結果查詢出來。這是它們的區別。如果一對一關系中先查詢從屬對象,然后得到從屬中的主對象時(即把上面測試類中的注釋1, 2都去掉再運行),控制臺打印信息如下:

    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可以看出,這種先查從對象,然后得到從屬對象中的主對象,要經過兩次查詢才能得到查詢結果。

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

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

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

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

    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也查詢出來了。那為什么一對一中查詢主對象時,不能實現懶加載呢??大家可以看看person表的結構,你從表結構中根本不能決斷出Person對象有沒有相應的IdCard對象,所以它無法給setIdCard賦值(hibernate不能想當然的認為你有值,給你new一個代理對象給它),所以它一定要去查詢相關聯的對象表,看是否有與此Person對應的IdCard記錄。而如果查詢的是從對象IdCard時,因為idcard中的id是一個person表的一個外鍵,所以它必定有一個相對應的Person對象(因為有constrained=true),所以它可以先返回給你一個代理對象,當你真正需要Person對象的數據時,它再去查詢數據庫。

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

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

    從打印信息可以看出,查詢從對象IdCard時實現了懶加載功能,因為它只查詢了IdCard對象,而關聯的Person對象它沒有進行查詢。

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

    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

    它就進行了兩次查詢,將IdCard關聯的Person對象也進行了查詢。因為訪問這些懶加載對象(代理對象)的屬性(getId和getClass除外)時,hibernate會初始化這些代理.

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

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

    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)進行測試,此時控制臺打印信息如下:

    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=?
    雖然也不實現懶加載功能,一次性將主從對象都查詢出來,但此時是經過兩次查詢才得到結果。

    如果修改IdCard.hbm.xml映射文件,增加lazy="proxy",如下所示,與缺省時一樣的效果,因為缺省時,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"/>??
  • ?

    二、唯一外鍵方式實現一對一

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

    ?hibernate一對一唯一外鍵關聯映射(雙向關聯Person<---->IdCard)
    一對一唯一外鍵雙向關聯,需要在另一端(person),添加<one-to-one>標簽,指示hibernate如何加載
    其關聯對象,默認根據主鍵加載idcard,外鍵關聯映射中,因為兩個實體采用的是idcard的外鍵維護的關系, 所以不能指定主鍵加載idcard,而要根據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,這樣就限制了多的一端的多重性為一???
  • ????????????通過這種手段映射一對一唯一外鍵關聯?-->??
  • ????????<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標簽也行,但那樣就變成了單向關聯(IdCard?----》?Person)?,也就是當知道IdCard后,能找到它屬于的對應的人,但知道某人后,卻無法找到相對應的IdCard-->??
  • ????????<one-to-one?name="idCard"?property-ref="person"/>??
  • ????</class>??
  • </hibernate-mapping>??
  • ?實體類不用修改,還是用上面的測試類進行測試即可。

    保存測試類運行后,相對共享主鍵方式的one-to-one,id_card表的結構發生了變化,表結構如下所示:

    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;

    數據庫表中記錄如下:

    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/>這一項的話,運行測試:

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

    ?java.lang.NullPointerException

    因為這種關系成了IdCard--->Person的單向關聯了。知道了Person,找不到對應的IdCard.

    當運行如下測試時:

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

    ?

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

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

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

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。