码农小汪-Hibernate学习8-hibernate关联关系注解表示@OneToMany mappedBy @ManyToMany @JoinTable...
近期我也是有點(diǎn)郁悶,究竟是程序中處理關(guān)聯(lián)關(guān)系。還是直接使用外鍵處理關(guān)聯(lián)關(guān)系呢?這個(gè)的說(shuō)法不一致!程序中處理這樣的關(guān)聯(lián)關(guān)系的話。自己去維護(hù)這樣的約束。這樣的非常樂(lè)觀的一種做法!或者是直接在數(shù)據(jù)庫(kù)中處理這樣的直接的外鍵關(guān)聯(lián),悲觀的做法!剛剛看到個(gè)帖子。有的公司表中一個(gè)外鍵都沒(méi)得。直接在程序中處理這樣的關(guān)聯(lián)關(guān)系。假設(shè)在Hibernate中處理外鍵關(guān)系的話。我們首先得有個(gè)主表的對(duì)象吧,然后在創(chuàng)建外鍵。感覺(jué)有點(diǎn)啰嗦。為啥不直接操作呢!
我僅僅要曉得你這個(gè)Id是外鍵即可了。各有各的說(shuō)法。我想你也在思考這個(gè)問(wèn)題。
現(xiàn)實(shí)的世界中確實(shí)非常少有孤立純?cè)诘臇|西。大多都是兩者之間純?cè)谀撤N關(guān)系的。有單向關(guān)系 僅僅能通過(guò)老師訪問(wèn)學(xué)生。或者學(xué)生訪問(wèn)老師
或者雙向關(guān)系 兩個(gè)都能夠相互的訪問(wèn)
單向關(guān)系
1-1
1-N
N-1
N-N
雙向關(guān)系
1-1
1-N
N-N
單向N_1關(guān)聯(lián)是最多的,多個(gè)人住同一個(gè)地址。我們僅僅須要從人這一端知道他的住址即可了,不是必需知道某個(gè)地址的用戶。
為了讓我們兩個(gè)持久化實(shí)體關(guān)聯(lián)。程序在N的一端添加持久化實(shí)體的一個(gè)屬性,該屬性指向引用1的那一端的關(guān)聯(lián)實(shí)體
對(duì)于N-1(不管是單向關(guān)聯(lián)還是雙向關(guān)聯(lián)),都僅僅須要在N的一端使用@ManyToONe修飾關(guān)聯(lián)實(shí)體的屬性
有以下的一些屬性,事實(shí)上之前我也說(shuō)過(guò)的,非常easy忘記。沒(méi)事的時(shí)候自己看看
| Cascade | 級(jí)聯(lián)操作策略CascadeType.ALL…. |
| Fetch | 抓取關(guān)聯(lián)實(shí)體的策略,之前說(shuō)過(guò)FechType.Lazy 延遲和馬上 |
| targetEntity | 該屬性的關(guān)聯(lián)實(shí)體的類名,在默認(rèn)情況下通過(guò)反射獲得類名 |
默認(rèn)情況下我們的targetEntity無(wú)需指定這個(gè)屬性的。但在一些特殊的情況下,比如使用@OneToMany.@ManyToMany 修飾 1-N N-N關(guān)聯(lián)的時(shí)候。關(guān)聯(lián)實(shí)體集合不帶泛型信息就必須指定了
無(wú)連接的N-1
無(wú)連接也就是不須要第三張表,維護(hù)我們的關(guān)聯(lián)關(guān)系。對(duì)于N_1關(guān)聯(lián)關(guān)系,我們僅僅須要在N的一端添加一列外鍵即可。
讓外鍵的值記錄到該屬性的實(shí)體即可。
Hibernate使用@JoinColumn來(lái)修飾代表關(guān)聯(lián)實(shí)體的屬性,用于映射底層的外鍵列。
這樣的就不使用連接表了
好啦,我們看一下樣例
多個(gè)人相應(yīng)同一個(gè)地址
@Entity @Table(name="person_inf") public class Person {@Id @Column(name="person_id")@GeneratedValue(strategy=GenerationType.IDENTITY)private Integer id;private String name;private int age;// 定義該P(yáng)erson實(shí)體關(guān)聯(lián)的Address實(shí)體@ManyToOne(targetEntity=Address.class)// 映射外鍵列,指定外鍵列的列名為address_id、不同意為空@JoinColumn(name="address_id" , nullable=false)@Cascade(CascadeType.ALL)private Address address;........ }Address 里面非常正常就一個(gè)Id。和地址具體他們建立的表什么樣子呢?
person_inf
person_id age name address_id
address_inf
address_id addressDetail
怎樣操作對(duì)象呢,由于address_id 是一個(gè)外鍵。
假設(shè)我們保存一個(gè)Person對(duì)象在我們的表中的話。我們應(yīng)該首先有一個(gè)Address 對(duì)象吧。
能夠是存在數(shù)據(jù)庫(kù)中的。也能夠才瞬態(tài)對(duì)象。我們?cè)诓迦氲臅r(shí)候級(jí)聯(lián)操作。會(huì)先插入address_inf這個(gè)表中,然后才干夠使用外接啦。不然會(huì)報(bào)錯(cuò)的,由于沒(méi)有存在的外鍵,肯定不行啦~
Session session = HibernateUtil.currentSession();Transaction tx = session.beginTransaction();// 創(chuàng)建一個(gè)Person對(duì)象Person p = new Person();// 創(chuàng)建一個(gè)瞬態(tài)的Address對(duì)象Address a = new Address("廣州天河"); p.setName("Test");p.setAge(21);// 設(shè)置Person和Address之間的關(guān)聯(lián)關(guān)系p.setAddress(a);// 持久化Person對(duì)象session.persist(p);//級(jí)聯(lián)的插入操作哦~。地址一定先于person插入數(shù)據(jù)表中,這里必須設(shè)置級(jí)聯(lián)操作,不然要報(bào)錯(cuò)// 創(chuàng)建一個(gè)瞬態(tài)的Address對(duì)象Address a2 = new Address("上海虹口"); // 改動(dòng)持久化狀態(tài)的Person對(duì)象p.setAddress(a2); tx.commit();HibernateUtil.closeSession();有連接的N-1
我們的關(guān)聯(lián)關(guān)系的維護(hù)讓第三張表來(lái)維護(hù)啦。
對(duì)于大部分的N_1單向關(guān)系,僅僅要基于外鍵的關(guān)聯(lián)關(guān)系維護(hù)已經(jīng)夠了。
假設(shè)有須要使用連接表來(lái)維護(hù)關(guān)聯(lián)關(guān)系,程序能夠使用連接表顯示的維護(hù)這樣的關(guān)系,所謂連接表就是建立第三張表格來(lái)維護(hù)我們的關(guān)系即可了。使用@JoinTable
以下的是java給的樣例,除了這些屬性外,我們還能夠指定targetEntity。指定關(guān)聯(lián)的實(shí)體是哪個(gè)!
也就是生成表的是哪個(gè)表所相應(yīng)的實(shí)體。
@JoinTable(name="CUST_PHONE",//相對(duì)于當(dāng)前實(shí)體的外鍵,的列名。參照的列名,也就是數(shù)據(jù)表中的名字 joinColumns= @JoinColumn(name="CUST_ID", referencedColumnName="ID"), //這個(gè)也是個(gè)外鍵,僅僅是不說(shuō)當(dāng)前實(shí)體里面的屬性。 inverseJoinColumns= @JoinColumn(name="PHONE_ID", referencedColumnName="ID") )
我們來(lái)看個(gè)樣例就知道啦
@Entity @Table(name="person_inf") public class Person {// 標(biāo)識(shí)屬性@Id @Column(name="person_id")@GeneratedValue(strategy=GenerationType.IDENTITY)private Integer id;private String name;private int age;// 定義該P(yáng)erson實(shí)體關(guān)聯(lián)的Address實(shí)體@ManyToOne(targetEntity=Address.class)// 顯式使用@JoinTable映射連接表@JoinTable(name="person_address", // 指定連接表的表名為person_address// 指定連接表中person_id外鍵列,參照到當(dāng)前實(shí)體相應(yīng)表的主鍵列joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id", unique=true),// 指定連接表中address_id外鍵列,參照到當(dāng)前實(shí)體的關(guān)聯(lián)實(shí)體相應(yīng)表的主鍵列inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id"))private Address address; ..... @Entity @Table(name="address_inf") public class Address {// 標(biāo)識(shí)屬性@Id @Column(name="address_id")@GeneratedValue(strategy=GenerationType.IDENTITY)private int addressId;// 定義地址具體信息的成員變量private String addressDetail; }這里產(chǎn)生的表的話,曾經(jīng)的person的表不會(huì)改變address也不會(huì)變
僅僅是添加一個(gè)外表
person_address ——table
address_id person_id
使用連接表維護(hù)關(guān)系
單向1-1關(guān)聯(lián)
看上去 1-1 和N-1 幾乎相同啊,都須要在持久化實(shí)體中添加代表關(guān)聯(lián)實(shí)體的成員變量,從代碼上看沒(méi)得什么差別。由于N的一端和1的一端都能夠直接的訪問(wèn)關(guān)聯(lián)的實(shí)體,。
不管單向的還是雙向的1-1關(guān)聯(lián),都須要使用@OneToOne修飾關(guān)聯(lián)實(shí)體的屬性
有以下的
級(jí)聯(lián)操作,抓取屬性。optional 關(guān)聯(lián)關(guān)系是否可選。目標(biāo)關(guān)聯(lián)實(shí)體的類名targetEntity.還有個(gè)重要的
mappedBy:該屬性合法的屬性值為關(guān)聯(lián)實(shí)體的屬性名。該屬性指定關(guān)聯(lián)實(shí)體中的哪個(gè)屬性可引用當(dāng)前的實(shí)體
樣例:基于外鍵的單向 1-1 關(guān)聯(lián),無(wú)連接表
@Entity @Table(name="person_inf") public class Person {// 標(biāo)識(shí)屬性@Id @Column(name="person_id")@GeneratedValue(strategy=GenerationType.IDENTITY)private Integer id;private String name;private int age;// 定義該P(yáng)erson實(shí)體關(guān)聯(lián)的Address實(shí)體@OneToOne(targetEntity=Address.class)// 映射名為address_id的外鍵列,參照關(guān)聯(lián)實(shí)體相應(yīng)表的addres_id主鍵列@JoinColumn(name="address_id", referencedColumnName="address_id" , unique=true)private Address address;地址肯定是獨(dú)一無(wú)二的嘛,對(duì)不正確!添加unique約束~..... }有連接表的也是幾乎相同,理解啦買即可了
@Entity @Table(name="person_inf") public class Person {// 標(biāo)識(shí)屬性@Id @Column(name="person_id")@GeneratedValue(strategy=GenerationType.IDENTITY)private Integer id;private String name;private int age;// 定義該P(yáng)erson實(shí)體關(guān)聯(lián)的Address實(shí)體@OneToOne(targetEntity=Address.class)@JoinTable(name="person_address",joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id" , unique=true),inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id", unique=true))private Address address;...... }上面的東西,我相信僅僅要第一個(gè)看懂了即可了,跟著畫樣子澀。1-1嘛。肯定不能一樣的澀。
單向的1-N
1的一端要訪問(wèn)N的一端。肯定的加個(gè)集合澀和前面的集合非常類似,可是如今的集合里的元素是關(guān)聯(lián)的實(shí)體啦。對(duì)于單向的1—N關(guān)聯(lián)關(guān)系。
僅僅須要在1的一端加入set類型的成員變量,記錄全部的關(guān)聯(lián)的實(shí)體。
即可了。具體怎么操作,我們慢慢的說(shuō)來(lái)。
一個(gè)個(gè)字的打還是能夠的。添加自己的理解
@OneToMany
級(jí)聯(lián)。抓取,目標(biāo)實(shí)體,mappedBy
無(wú)連接表的單向1-N
1個(gè)人有多個(gè)住處~~~貪官!
不然怎么買的起這么多房子,如今的房?jī)r(jià)你又不是不知道。哼~
@Entity @Table(name="person_inf") public class Person {@Id @Column(name="person_id")@GeneratedValue(strategy=GenerationType.IDENTITY)private Integer id;private String name;private int age;// 定義該P(yáng)erson實(shí)體全部關(guān)聯(lián)的Address實(shí)體,沒(méi)有指定cascade屬性@OneToMany(targetEntity=Address.class)// 映射外鍵列。此處映射的外鍵列將會(huì)加入到關(guān)聯(lián)實(shí)體相應(yīng)的數(shù)據(jù)表中。為啥呢?@JoinColumn(name="person_id" , referencedColumnName="person_id")private Set<Address> addresses= new HashSet<>();........}這里的外鍵列不會(huì)添加到當(dāng)前實(shí)體相應(yīng)的數(shù)據(jù)表中,而是添加到,關(guān)聯(lián)實(shí)體Address相應(yīng)的數(shù)據(jù)表中,有點(diǎn)特殊!
為什么。之前我們使用set集合的時(shí)候都必須在添加一個(gè)表記得?僅僅只是這里添加到了關(guān)聯(lián)實(shí)體里面去了。
而不是在添加一張表~~
N的端不維護(hù)關(guān)系,沒(méi)得變化~
有連接的1-N
@Entity @Table(name="person_inf") public class Person {// 標(biāo)識(shí)屬性@Id @Column(name="person_id")@GeneratedValue(strategy=GenerationType.IDENTITY)private Integer id;private String name;private int age;// 定義該P(yáng)erson實(shí)體全部關(guān)聯(lián)的Address實(shí)體@OneToMany(targetEntity=Address.class)// 映射連接表為person_address@JoinTable(name="person_address",// 定義連接表中名為person_id的外鍵列。該外鍵列參照當(dāng)前實(shí)體相應(yīng)表的主鍵列joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id"),// 定義連接表中名為address_id的外鍵列。// 該外鍵列參照當(dāng)前實(shí)體的關(guān)聯(lián)實(shí)體相應(yīng)表的主鍵列inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id", unique=true))private Set<Address> addresses= new HashSet<>(); ... }這里是1對(duì)N 1個(gè)人有多個(gè)住的地方,可是每一個(gè)都是不一樣的,所以要添加unique約束
由于採(cǎi)用連接表了,我們的Person表中沒(méi)有存在維護(hù)連接關(guān)系,能夠隨意的持久化操作。
1個(gè)person 2個(gè)adress 要插入5次操作哦
自己想想為什么?
單向的N-N也是須要的
@ManyToMany
N-N關(guān)系必須須要連接表啦,和有連接的1-N類似,可是要把unique約束去掉啦~
直接改動(dòng)啦,上面那個(gè)~
轉(zhuǎn)載于:https://www.cnblogs.com/wzzkaifa/p/7354159.html
總結(jié)
以上是生活随笔為你收集整理的码农小汪-Hibernate学习8-hibernate关联关系注解表示@OneToMany mappedBy @ManyToMany @JoinTable...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 手游php,PHP响应式手游APP软件游
- 下一篇: 动态SQL中变量赋值