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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

【Hibernate步步为营】--关联映射之多对一

發(fā)布時(shí)間:2025/6/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Hibernate步步为营】--关联映射之多对一 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
上篇文章討論了Hibernate的基本映射,一個(gè)實(shí)體類(lèi)對(duì)應(yīng)著一張表,在相應(yīng)的Hibernate Mapping文件中使用<class>標(biāo)簽映射。并且實(shí)體類(lèi)中的普通屬性對(duì)應(yīng)著表字段,使用<property>標(biāo)簽映射。另外在構(gòu)造實(shí)體類(lèi)時(shí)應(yīng)注意:在實(shí)體類(lèi)中應(yīng)實(shí)現(xiàn)無(wú)參的默認(rèn)的構(gòu)造函數(shù),提供一個(gè)標(biāo)示,建議不要使用final修飾實(shí)體類(lèi),為實(shí)體類(lèi)生成getter和setter方法,最后介紹了幾種主要的主鍵生成策略,接下來(lái)討論多對(duì)一映射。


一、關(guān)聯(lián)映射之多對(duì)一


??????? 對(duì)于多對(duì)一關(guān)聯(lián)映射其實(shí)很容易理解,在思考時(shí)可以把它看做人員和組之間的關(guān)系,在一個(gè)組中會(huì)有多個(gè)人員,所以這就出現(xiàn)了多對(duì)一的關(guān)系多個(gè)人會(huì)同屬于一個(gè)組,那么在設(shè)計(jì)關(guān)系模型時(shí)就會(huì)有兩種設(shè)計(jì)方法,一種是將組號(hào)作為外鍵添加到用戶表中,另外一種是單獨(dú)生成第三張表,將用戶id號(hào)和組id號(hào)相關(guān)聯(lián)。對(duì)于第一種設(shè)計(jì)方法它的關(guān)系模型可用下表表示:


?????? 這種多對(duì)一關(guān)聯(lián)映射反應(yīng)到對(duì)象模型中它是一種聚合關(guān)系,User是group的一部分,group中存在User,它們兩個(gè)的生命周期是不相同的,可反應(yīng)為下圖:


????? 那么這種多對(duì)一關(guān)系映射在Hibernate中是如何設(shè)置的呢?下面將會(huì)介紹兩種方法,使用<many-to-one>標(biāo)簽直接映射,或者使用<many-to-one>的cascade級(jí)聯(lián)修改表。


? 1、Many-to-one直接映射


?????? 從字面意思上就能夠理解,它是指多對(duì)一的關(guān)系,many指的是多的一端,one指的是少的一端,在使用時(shí)往往在多的一端的hbm中使用該標(biāo)簽,并將<many-to-one>的name屬性設(shè)置為該映射文件對(duì)應(yīng)的類(lèi)中的one一端的屬性,如:<many-to-one name="group" column="groupid"></many-to-one>,該標(biāo)簽添加在了User.hbm.xml中,它對(duì)應(yīng)many;標(biāo)簽中的name值為group對(duì)映射one,并且在User.java中會(huì)有一個(gè)名為group的屬性。接下來(lái)看下具體實(shí)現(xiàn)實(shí)現(xiàn)的代碼類(lèi)。

??? (1)User.java類(lèi)代碼,其中有一個(gè)名為group的屬性,它將會(huì)作為<many-to-one>的one一端的name值。

[java] view plain copy
  • public?class?User?{??
  • ????private?String?name;??
  • ????public?String?GetName(){??
  • ????????return?name;??
  • ????}??
  • ????public?void?SetName(String?name){??
  • ????????this.name=name;??
  • ????}??
  • ??????
  • ????private?Group?group;??
  • ????public?Group?GetGroup(){??
  • ????????return?group;??
  • ????}??
  • ????public?void?SetGroup(Group?group){??
  • ????????this.group=group;??
  • ????}??
  • }??

  • ?????? (2)User.hbm.xml中的<many-to-one>,name的值為User.java中one端的屬性值,它會(huì)在數(shù)據(jù)庫(kù)中生成一個(gè)新列,可以將該新列理解為User表的外鍵。

    [html] view plain copy
  • <?xml?version="1.0"?>??
  • <!DOCTYPE?hibernate-mapping?PUBLIC?"-//Hibernate/Hibernate?Mapping?DTD?3.0//EN"??
  • "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">??
  • <!--?Generated?2014-5-14?23:39:25?by?Hibernate?Tools?3.4.0.CR1?-->??
  • <hibernate-mapping>??
  • ????<class?name="com.hibernate.User"?table="USER">??
  • ????????<id?name="id"?type="java.lang.Long">??
  • ????????????<column?name="ID"?/>??
  • ????????????<generator?class="assigned"?/>??
  • ????????</id>??
  • ??????????
  • ????????<!--?name的值group為User.java中的一個(gè)對(duì)應(yīng)的one中的一個(gè)屬性,它會(huì)自動(dòng)在表中生成一列,所以使用column對(duì)列進(jìn)行了重命名?-->??
  • ????????<many-to-one?name="group"?column="groupid"></many-to-one>??
  • ??????????
  • ????</class>??
  • </hibernate-mapping>??

  • ???? (3)測(cè)試上面的映射關(guān)系,向表中寫(xiě)入兩個(gè)User對(duì)象分別為user1和user2,命名為張三和李四,使用session保存對(duì)象,向數(shù)據(jù)庫(kù)中寫(xiě)入數(shù)據(jù),代碼如下:

    [java] view plain copy
  • public?void?testSave1(){??
  • ??????????
  • ????????Session?session=null;??
  • ????????try{??
  • ????????????session=GetSession.getSession();??
  • ????????????session.beginTransaction();??
  • ??????????????
  • ????????????Group?group=new?Group();??
  • ????????????group.SetName("動(dòng)力節(jié)點(diǎn)");??
  • ??????????????
  • ????????????User?user1=new?User();??
  • ????????????user1.SetName("張三");??
  • ????????????user1.SetGroup(group);??
  • ??????????????
  • ????????????User?user2=new?User();??
  • ????????????user2.SetName("李四");??
  • ????????????user2.SetGroup(group);??
  • ??????????????
  • ????????????session.save(user1);??
  • ????????????session.save(user2);??
  • ??????????????
  • ????????????//會(huì)報(bào)TransientObjectException錯(cuò)誤??
  • ????????????//在清理緩存時(shí)發(fā)生錯(cuò)誤TransientObjectException??
  • ????????????//因?yàn)镚roup為T(mén)ransient狀態(tài),沒(méi)有被Session,在數(shù)據(jù)庫(kù)中沒(méi)有匹配的數(shù)據(jù)??
  • ????????????//而User為Persistent狀態(tài),在清理緩存時(shí)Hibernate在緩存中無(wú)法找到Group對(duì)象??
  • ????????????//揭露:Persistent狀態(tài)的對(duì)象不能引用Transient狀態(tài)的對(duì)象??
  • ????????????//該問(wèn)題在testSave2方法中更改??
  • ????????????session.getTransaction().commit();??
  • ????????}catch(Exception?e){??
  • ??????????????
  • ????????????e.printStackTrace();??
  • ????????????session.getTransaction().rollback();??
  • ????????}finally{??
  • ????????????GetSession.CloseSession(session);??
  • ????????}??
  • ????}??

  • ??????? 但是使用上面的代碼在執(zhí)行寫(xiě)入時(shí)會(huì)報(bào)錯(cuò)TransientObjectException,這是因?yàn)樵诒4鎁ser對(duì)象時(shí)它會(huì)按照<many-to-one>中添加的group去內(nèi)存中查找group對(duì)象,但是上面的代碼中g(shù)roup對(duì)象一直都是在Transient狀態(tài)中,并沒(méi)有被session管理,也就是說(shuō)查找不到session對(duì)象,而User對(duì)象進(jìn)入了Persistent狀態(tài),于是會(huì)報(bào)此錯(cuò)誤。正確的代碼如下:
    [java] view plain copy
  • public?void?testSave2(){??
  • ??????????????
  • ????Session?session=null;??
  • ????try{??
  • ????????session=GetSession.getSession();??
  • ????????session.beginTransaction();??
  • ??????????
  • ????????Group?group=new?Group();??
  • ????????group.SetName("動(dòng)力節(jié)點(diǎn)");??
  • ????????session.save(group);???????//此處將group對(duì)象設(shè)置為Persistent對(duì)象??
  • ??????????
  • ????????User?user1=new?User();??
  • ????????user1.SetName("張三");??
  • ????????user1.SetGroup(group);??
  • ??????????
  • ????????User?user2=new?User();??
  • ????????user2.SetName("李四");??
  • ????????user2.SetGroup(group);??
  • ??????????
  • ????????session.save(user1);??
  • ????????session.save(user2);??
  • ??????????
  • ????????//可以正確的保存數(shù)據(jù)??
  • ????????//因?yàn)镚roup和User都是Persistent狀態(tài)的對(duì)象??
  • ????????//所以在Hibernate清理緩存時(shí)在session中可以找到關(guān)聯(lián)對(duì)象??
  • ????????session.getTransaction().commit();??
  • ????}catch(Exception?e){??
  • ??????????
  • ????????e.printStackTrace();??
  • ????????session.getTransaction().rollback();??
  • ????}finally{??
  • ????????GetSession.CloseSession(session);??
  • ????}??
  • }??

  • ? 2、級(jí)聯(lián)映射


    ???????? 除了上面所說(shuō)的將group對(duì)象和user對(duì)象都轉(zhuǎn)化到Persistent對(duì)象外,還可以使用cascade級(jí)聯(lián)映射屬性,在<many-to-one>屬性中添加cascade屬性,并復(fù)制為save-update,在group對(duì)象并非為Persistent狀態(tài)時(shí)即可寫(xiě)入數(shù)據(jù)庫(kù)。這樣只需要將兩個(gè)user對(duì)象的Group屬性設(shè)置為同一個(gè)group對(duì)象即可實(shí)現(xiàn)多對(duì)一的映射關(guān)系,此時(shí)User.hbm.xml中對(duì)應(yīng)的內(nèi)容為如下代碼:

    [html] view plain copy
  • <?xml?version="1.0"?>??
  • <!DOCTYPE?hibernate-mapping?PUBLIC?"-//Hibernate/Hibernate?Mapping?DTD?3.0//EN"??
  • "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">??
  • <!--?Generated?2014-5-14?23:39:25?by?Hibernate?Tools?3.4.0.CR1?-->??
  • <hibernate-mapping>??
  • ????<class?name="com.hibernate.User"?table="USER">??
  • ????????<id?name="id"?type="java.lang.Long">??
  • ????????????<column?name="ID"?/>??
  • ????????????<generator?class="assigned"?/>??
  • ????????</id>??
  • ??????????
  • ????????<!--?級(jí)聯(lián)修改表?-->??
  • ????????<many-to-one?name="group"?column="groupid"?cascade="save-update"></many-to-one>??
  • ??????????
  • ????</class>??
  • </hibernate-mapping>??

  • ??? ?? Note:cascade設(shè)置為save-update后即可實(shí)現(xiàn)向數(shù)據(jù)庫(kù)中級(jí)聯(lián)修改、添加和刪除,但是具體的級(jí)聯(lián)查詢(xún)操作卻不可以。
    ?????? 對(duì)應(yīng)的測(cè)試配置文件的方法為如下代碼:

    [java] view plain copy
  • //級(jí)聯(lián)cascade??
  • public?void?testSave3(){??
  • ??????
  • ????Session?session=null;??
  • ????try{??
  • ????????session=GetSession.getSession();??
  • ????????session.beginTransaction();??
  • ??????????
  • ????????Group?group=new?Group();??
  • ????????group.SetName("動(dòng)力節(jié)點(diǎn)");??
  • ??????????
  • ????????User?user1=new?User();??
  • ????????user1.SetName("張三");??
  • ????????user1.SetGroup(group);??
  • ??????????
  • ????????User?user2=new?User();??
  • ????????user2.SetName("李四");??
  • ????????user2.SetGroup(group);??
  • ??????????
  • ????????session.save(user1);??
  • ????????session.save(user2);??
  • ??????????
  • ????????//沒(méi)有拋出TransientObjectException異常??
  • ????????//因?yàn)槭褂昧思?jí)聯(lián)??
  • ????????//Hibernate會(huì)首先保存User的關(guān)聯(lián)對(duì)象Group??
  • ????????//Group和User就都是Persistent狀態(tài)的對(duì)象了??
  • ????????session.getTransaction().commit();??
  • ????}catch(Exception?e){??
  • ????????e.printStackTrace();??
  • ????????session.getTransaction().rollback();??
  • ????}finally{??
  • ????????GetSession.CloseSession(session);??
  • ????}??
  • }??


  • ? 3、對(duì)比升華


    ??????? 兩種方法同樣實(shí)現(xiàn)了多對(duì)一的映射方法,結(jié)果上是相同的,但在實(shí)現(xiàn)上很不相同。無(wú)論是第一種還是第二種采用的都是<many-to-one>在many一端的映射文件中添加該標(biāo)簽,并將標(biāo)簽的name屬性賦值為該映射文件注冊(cè)的類(lèi)中的one一端的屬性值,這樣就完成了多對(duì)一的基本映射,這是相同點(diǎn)。不同點(diǎn)是直接映射關(guān)系沒(méi)有采用Hibernate字段的屬性,這樣在實(shí)現(xiàn)上較靈活,不但支持增刪改,而且可以查詢(xún);第二種的cascade級(jí)聯(lián)修改則采用了Hibernate提供的方法,此種方法只支持增刪改,并不支持查詢(xún)。

    結(jié)語(yǔ)

    ???????

    ?????? 文章介紹了兩種方法來(lái)實(shí)現(xiàn)多對(duì)一的映射,這兩種方法在實(shí)現(xiàn)結(jié)果上是相同的,都是采用的<many-to-one>多對(duì)一標(biāo)簽,實(shí)現(xiàn)上很簡(jiǎn)單。需要注意的是第一種方法必須將組對(duì)象和用戶全部轉(zhuǎn)化為T(mén)ransient狀態(tài),都必須被Session管理這樣在保存時(shí)才能夠在Session中查找到兩種對(duì)象。多對(duì)一映射是經(jīng)常使用的,另外還有其它的映射關(guān)系,將會(huì)在下篇文章中討論。

    《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的【Hibernate步步为营】--关联映射之多对一的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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