深入解析Java的Hibernate框架中的一對(duì)一關(guān)聯(lián)映射
作為一個(gè)ORM框架,hibernate肯定也需要滿足我們實(shí)現(xiàn)表與表之間進(jìn)行關(guān)聯(lián)的需要。hibernate在關(guān)聯(lián)方法的實(shí)現(xiàn)很簡(jiǎn)單。下面我們先來(lái)看看一對(duì)一的做法:
不多說(shuō)了,我們直接上代碼:
兩個(gè)實(shí)體類(lèi),TUser和TPassport:
public class TUser implements Serializable{ private static final long serialVersionUID = 1L; private int id; private int age; private String name; private TPassport passport; //省略Get/Set方法 } public class TPassport implements Serializable{ private static final long serialVersionUID = 1L; private int id; private String serial; private int expiry; private TUser user; //省略Get/Set方法 }
下面我們看一下映射文件有什么不同:
<hibernate-mapping package="org.hibernate.tutorial.domain4"> <class name="TUser" table="USER4"> <id name="id" column="id"> <generator class="native" /> </id> <property name="name" type="java.lang.String" column="name"/> <property name="age" type="java.lang.Integer" column="age"/> <one-to-one name="passport" class="TPassport" cascade="all" outer-join="true" /> </class> </hibernate-mapping>
這里我們看到有一個(gè)新標(biāo)簽,one-to-one,它表明當(dāng)前類(lèi)與所對(duì)應(yīng)的類(lèi)是一對(duì)一的關(guān)系,cascade是級(jí)聯(lián)關(guān)系,all表明無(wú)論什么情況都進(jìn)行級(jí)聯(lián),即當(dāng)對(duì)TUser類(lèi)進(jìn)行操作時(shí),TPassport也會(huì)進(jìn)行相應(yīng)的操作,outer-join是指是否使用outer join語(yǔ)句。
我們?cè)倏戳硗庖粋€(gè)TPassport的映射文件:
<hibernate-mapping package="org.hibernate.tutorial.domain4"> <class name="TPassport" table="passport4"> <id name="id" column="id"> <generator class="foreign" > <param name="property">user</param> </generator> </id> <property name="serial" type="java.lang.String" column="serial"/> <property name="expiry" type="java.lang.Integer" column="expiry"/> <one-to-one name="user" class="TUser" constrained="true" /> </class> </hibernate-mapping>
這里我們重點(diǎn)看到generator的class值,它為foreign表明參照外鍵,而參照哪一個(gè)是由param來(lái)進(jìn)行指定,這里表明參照User類(lèi)的id。而one-to-one標(biāo)簽中多了一個(gè)constrained屬性,它是告訴hibernate當(dāng)前類(lèi)存在外鍵約束,即當(dāng)前類(lèi)的ID根據(jù)TUser的ID進(jìn)行生成。
下面我們直接上測(cè)試類(lèi),這次測(cè)試類(lèi)沒(méi)有用JUnit而是直接Main方法來(lái)了:
public static void main(String[] args) { Configuration cfg = new Configuration().configure(); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); session.beginTransaction(); TUser user = new TUser(); user.setAge(20); user.setName("shunTest"); TPassport passport = new TPassport(); passport.setExpiry(20); passport.setSerial("123123123"); passport.setUser(user); user.setPassport(passport); session.save(user); session.getTransaction().commit(); }
代碼很簡(jiǎn)單,就不說(shuō)了。我們主要看這里:
session.save(user);
這里為什么我們只調(diào)用一個(gè)save呢,原因就在我們的TUser映射文件中的cascade屬性,它被設(shè)為all,即表明當(dāng)我們對(duì)TUser進(jìn)行保存,更新,刪除等操作時(shí),TPassport也會(huì)進(jìn)行相應(yīng)的操作,所以這里我們不用寫(xiě)session.save(passport)。我們看到后臺(tái):
Hibernate: insert into USER4 (name, age) values (?, ?) Hibernate: insert into passport4 (serial, expiry, id) values (?, ?, ?)
下面我們?cè)賮?lái)一個(gè)測(cè)試類(lèi),測(cè)試查詢:
public static void main(String[] args) { Configuration cfg = new Configuration().configure(); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); TUser user = (TUser)session.load(TUser.class,new Integer(3)); System.out.println(user.getName()+":"+user.getPassport().getSerial()); }
我們可以看到hibernate的SQL語(yǔ)句是:
Hibernate:
select tuser0_.id as id0_1_, tuser0_.name as name0_1_, tuser0_.age as age0_1_, tpassport1_.id as id1_0_, tpassport1_.serial as serial1_0_, tpassport1_.expiry as expiry1_0_ from USER4 tuser0_ left outer join passport4 tpassport1_ on tuser0_.id=tpassport1_.id where tuser0_.id=?
Hibernate:
select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.age as age0_0_ from USER4 tuser0_ where tuser0_.id=?
select tpassport0_.id as id1_0_, tpassport0_.serial as serial1_0_, tpassport0_.expiry as expiry1_0_ from passport4 tpassport0_ where tpassport0_.id=?
也許很多人會(huì)問(wèn)為什么測(cè)試的時(shí)候不用TPassport查出TUser呢,其實(shí)也可以的,因?yàn)樗鼈兪且粚?duì)一的關(guān)系,誰(shuí)查誰(shuí)都是一樣的。
外鍵關(guān)聯(lián)
現(xiàn)在我們看一下通過(guò)外鍵來(lái)進(jìn)行關(guān)聯(lián)的一對(duì)一關(guān)聯(lián)。
還是一貫的直接上例子:我們寫(xiě)了兩個(gè)實(shí)體類(lèi),TGroup和TUser
public class TGroup implements Serializable{ private static final long serialVersionUID = 1L; private int id; private String name; private TUser user; //省略Get/Set方法 } public class TUser implements Serializable{ private static final long serialVersionUID = 1L; private int id; private int age; private String name; private TGroup group; //省略Get/Set方法 }
實(shí)體類(lèi)完了我們就看一下映射文件:
<hibernate-mapping package="org.hibernate.tutorial.domain5"> <class name="TUser" table="USER5"> <id name="id" column="id"> <generator class="native" /> </id> <property name="name" type="java.lang.String" column="name"/> <property name="age" type="java.lang.Integer" column="age"/> <many-to-one name="group" class="TGroup" column="group_id" unique="true" /> </class> </hibernate-mapping>
這里我們看到是用many-to-one標(biāo)簽而不是one-to-one,為什么呢?
這里以前用的時(shí)候也沒(méi)多在注意,反正會(huì)用就行,但這次看了夏昕的書(shū)終于明白了,實(shí)際上這種通過(guò)外鍵進(jìn)行關(guān)聯(lián)方式只是多對(duì)一的一種特殊方式而已,我們通過(guò)unique="true"限定了它必須只能有一個(gè),即實(shí)現(xiàn)了一對(duì)一的關(guān)聯(lián)。
接下來(lái)我們看一下TGroup的映射文件:
<hibernate-mapping package="org.hibernate.tutorial.domain5"> <class name="TGroup" table="group5"> <id name="id" column="id"> <generator class="native" /> </id> <property name="name" type="java.lang.String" column="name"/> <one-to-one name="user" class="TUser" property-ref="group" /> </class> </hibernate-mapping>
這里,注意,我們又用到了one-to-one,表明當(dāng)前的實(shí)體和TUser是一對(duì)一的關(guān)系,這里我們不用many-to-one,而是通過(guò)one-to-one指定了TUser實(shí)體中通過(guò)哪個(gè)屬性來(lái)關(guān)聯(lián)當(dāng)前的類(lèi)TGroup。這里我們指定了TUser是通過(guò)group屬性和Tuser進(jìn)行關(guān)聯(lián)的。property-ref指定了通過(guò)哪個(gè)屬性進(jìn)行關(guān)聯(lián)。
下面我們看測(cè)試類(lèi):
public class HibernateTest { public static void main(String[] args) { Configuration cfg = new Configuration().configure(); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); session.beginTransaction(); TGroup group = new TGroup(); group.setName("testGroup"); TUser user = new TUser(); user.setAge(23); user.setName("test"); user.setGroup(group); group.setUser(user); session.save(group); session.save(user); session.getTransaction().commit(); session.close(); } }
注意,這次我們的代碼中需要進(jìn)行兩次的保存,因?yàn)樗鼈儗?duì)各自都有相應(yīng)的對(duì)應(yīng),只保存一個(gè)都不會(huì)對(duì)另外一個(gè)有什么操作。所以我們需要調(diào)用兩次保存的操作。最后進(jìn)行提交。
hibernate打印出語(yǔ)句:
Hibernate: insert into group5 (name) values (?) Hibernate: insert into USER5 (name, age, group_id) values (?, ?, ?)
這說(shuō)明我們正確地存入了兩個(gè)對(duì)象值。
我們寫(xiě)多一個(gè)測(cè)試類(lèi)進(jìn)行查詢:
public static void main(String[] args) { Configuration cfg = new Configuration().configure(); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); TUser user = (TUser)session.load(TUser.class,new Integer(1)); System.out.println("From User get Group:"+user.getGroup().getName()); TGroup group = (TGroup)session.load(TGroup.class,new Integer(1)); System.out.println("From Group get User:" + group.getUser().getName()); session.close(); }
我們都可以得到正確的結(jié)果,這表明我們可以通過(guò)兩個(gè)對(duì)象拿出對(duì)方的值,達(dá)到了我們的目的。
這個(gè)例子中用到的TGroup和TUser只是例子而已,實(shí)際上現(xiàn)實(shí)生活中的user一般都對(duì)應(yīng)多個(gè)group。
- Hibernate雙向一對(duì)一映射關(guān)系配置代碼實(shí)例
- Hibernatede 一對(duì)多映射配置方法(分享)
- hibernate一對(duì)多關(guān)聯(lián)映射學(xué)習(xí)小結(jié)
- Hibernate多對(duì)一單項(xiàng)關(guān)聯(lián)
- 舉例講解Java的Hibernate框架中的多對(duì)一和一對(duì)多映射
- java Hibernate 一對(duì)多自身關(guān)聯(lián)問(wèn)題
- Hibernate的一對(duì)一,一對(duì)多/多對(duì)一關(guān)聯(lián)保存的實(shí)現(xiàn)
相關(guān)文章
Java web實(shí)現(xiàn)賬號(hào)單一登錄,防止同一賬號(hào)重復(fù)登錄(踢人效果)
這篇文章主要介紹了Java web實(shí)現(xiàn)賬號(hào)單一登錄,防止同一賬號(hào)重復(fù)登錄,有點(diǎn)類(lèi)似于qq登錄踢人效果,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10SpringBoot深入講解單元測(cè)試與熱部署應(yīng)用
這篇文章介紹了SpringBoot單元測(cè)試與熱部署,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06SpringBoot實(shí)現(xiàn)文件下載功能的方式分享
這篇文章主要為大家詳細(xì)介紹了SpringBoot這哪個(gè)實(shí)現(xiàn)文件下載功能的幾種方式,文中的實(shí)現(xiàn)方法簡(jiǎn)介易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03Nacos入門(mén)過(guò)程的坑--獲取不到配置的值問(wèn)題
這篇文章主要介紹了Nacos入門(mén)過(guò)程的坑--獲取不到配置的值問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01劍指Offer之Java算法習(xí)題精講數(shù)組與字符串題
跟著思路走,之后從簡(jiǎn)單題入手,反復(fù)去看,做過(guò)之后可能會(huì)忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會(huì)發(fā)現(xiàn)質(zhì)的變化2022-03-03Spring Cloud OpenFeign REST服務(wù)客戶端原理及用法解析
這篇文章主要介紹了Spring Cloud OpenFeign REST服務(wù)客戶端原理及用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10Java用Cookie限制點(diǎn)贊次數(shù)(簡(jiǎn)版)
最近做了一個(gè)項(xiàng)目,其中有項(xiàng)目需求是,要用cookie實(shí)現(xiàn)限制點(diǎn)贊次數(shù),特此整理,把實(shí)現(xiàn)代碼分享給大家供大家學(xué)習(xí)2016-02-02