更新時(shí)間:2022-05-30 10:02:42 來源:動(dòng)力節(jié)點(diǎn) 瀏覽1322次
這個(gè)快速的 Hibernate 教程將帶我們了解一個(gè)使用 JPA 注釋的一對(duì)多映射示例,它 是 XML 的替代方法。
我們還將了解什么是雙向關(guān)系,它們?nèi)绾卧斐刹灰恢拢约八袡?quán)的概念如何提供幫助。小伙伴們也可以關(guān)注動(dòng)力節(jié)點(diǎn)的Hibernate入門視頻教程,里面的內(nèi)容由淺到深,細(xì)致全面,適合沒有基礎(chǔ)的小伙伴學(xué)習(xí)。
簡(jiǎn)單來說,一對(duì)多映射就是將一個(gè)表中的一行映射到另一個(gè)表中的多行。
讓我們看一下下面的實(shí)體關(guān)系圖,看看一對(duì)多的關(guān)聯(lián):
對(duì)于此示例,我們將實(shí)現(xiàn)一個(gè)購物車系統(tǒng),其中每個(gè)購物車都有一個(gè)表,每個(gè)項(xiàng)目都有另一個(gè)表。一個(gè)購物車可以有很多物品,所以這里我們有一個(gè)一對(duì)多的映射。
這在數(shù)據(jù)庫級(jí)別的工作方式是我們有一個(gè)cart_id作為cart表中的主鍵,還有一個(gè)cart_id 作為items中的外鍵 。
我們?cè)诖a中執(zhí)行此操作的方式是使用@OneToMany。
讓我們 以反映數(shù)據(jù)庫中關(guān)系的方式將Cart類映射到 Item對(duì)象的集合:
public class Cart {
//...
@OneToMany(mappedBy="cart")
private Set<Item> items;
//...
}
我們還可以 使用@ManyToOne在每個(gè) Item中添加對(duì)Cart的引用,使其成為 雙向關(guān)系。雙向意味著我們能夠訪問 來自購物車的物品,也可以訪問 來自物品的購物車。
mappedBy屬性用于告訴 Hibernate 我們使用哪個(gè)變量來表示子類中的父類。
以下技術(shù)和庫用于開發(fā)實(shí)現(xiàn)一對(duì)多關(guān)聯(lián)的示例 Hibernate 應(yīng)用程序:
JDK 1.8 或更高版本
休眠5
Maven 3 或更高版本
H2數(shù)據(jù)庫
(1)數(shù)據(jù)庫設(shè)置
我們將使用 Hibernate 從域模型中管理我們的模式。換句話說,我們不需要提供 SQL 語句來創(chuàng)建各種表和實(shí)體之間的關(guān)系。因此,讓我們繼續(xù)創(chuàng)建 Hibernate 示例項(xiàng)目。
(2)Maven 依賴項(xiàng)
讓我們首先將 Hibernate 和 H2 驅(qū)動(dòng)程序依賴項(xiàng)添加到我們的pom.xml文件中。Hibernate 依賴項(xiàng)使用 JBoss 日志記錄,它會(huì)自動(dòng)添加為傳遞依賴項(xiàng):
休眠版本5.6.7.Final
H2驅(qū)動(dòng)版本2.1.212
請(qǐng)?jiān)L問 Maven 中央存儲(chǔ)庫以獲取最新版本的Hibernate和H2依賴項(xiàng)。
(3)休眠會(huì)話工廠
接下來,讓我們?yōu)槲覀兊臄?shù)據(jù)庫交互創(chuàng)建 Hibernate SessionFactory :
public static SessionFactory getSessionFactory() {
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(dbSettings())
.build();
Metadata metadata = new MetadataSources(serviceRegistry)
.addAnnotatedClass(Cart.class)
// other domain classes
.buildMetadata();
return metadata.buildSessionFactory();
}
private static Map<String, String> dbSettings() {
// return Hibernate settings
}
與映射相關(guān)的配置將使用模型類中的 JPA 注釋完成:
請(qǐng)注意,@OneToMany注釋用于定義Item 類中的屬性,該屬性將用于映射mappedBy變量。這就是為什么我們?cè)贗tem 類中有一個(gè)名為“ cart ”的屬性:
@Entity
@Table(name="ITEMS")
public class Item {
//...
@ManyToOne
@JoinColumn(name="cart_id", nullable=false)
private Cart cart;
public Item() {}
// getters and setters
}
同樣重要的是要注意@ManyToOne注釋與Cart類變量相關(guān)聯(lián)。@JoinColumn注釋引用映射的列。
在測(cè)試程序中,我們正在創(chuàng)建一個(gè)帶有main () 方法的類,用于獲取 Hibernate Session,并將模型對(duì)象保存到實(shí)現(xiàn)一對(duì)多關(guān)聯(lián)的數(shù)據(jù)庫中:
sessionFactory = HibernateAnnotationUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
tx = session.beginTransaction();
session.save(cart);
session.save(item1);
session.save(item2);
tx.commit();
System.out.println("Cart ID=" + cart.getId());
System.out.println("item1 ID=" + item1.getId()
+ ", Foreign Key Cart ID=" + item.getCart().getId());
System.out.println("item2 ID=" + item2.getId()
+ ", Foreign Key Cart ID=" + item.getCart().getId());
這是我們測(cè)試程序的輸出:
Session created
Hibernate: insert into CART values ()
Hibernate: insert into ITEMS (cart_id)
values (?)
Hibernate: insert into ITEMS (cart_id)
values (?)
Cart ID=7
item1 ID=11, Foreign Key Cart ID=7
item2 ID=12, Foreign Key Cart ID=7
Closing SessionFactory
正如我們?cè)诘?2 節(jié)中看到的,我們可以通過使用@ManyToOne注釋來指定多對(duì)一關(guān)系。多對(duì)一映射意味著該實(shí)體的許多實(shí)例映射到另一個(gè)實(shí)體的一個(gè)實(shí)例——一個(gè)購物車中的許多物品。
@ManyToOne注釋也讓我們可以創(chuàng)建雙向關(guān)系。我們將在接下來的幾小節(jié)中詳細(xì)介紹這一點(diǎn)。
(1)不一致和所有權(quán)
現(xiàn)在,如果Cart引用了Item,但 Item 又沒有引用Cart,我們的關(guān)系將是單向的。這些對(duì)象也將具有自然的一致性。
但在我們的例子中,這種關(guān)系是雙向的,帶來了不一致的可能性。
讓我們想象這樣一種情況,開發(fā)人員想將 item1添加到 cart1 實(shí)例,將 item2 添加到 cart2 實(shí)例,但是犯了一個(gè)錯(cuò)誤,導(dǎo)致cart2和item2之間的引用變得不一致:
Cart cart1 = new Cart();
Cart cart2 = new Cart();
Item item1 = new Item(cart1);
Item item2 = new Item(cart2);
Set<Item> itemsSet = new HashSet<Item>();
itemsSet.add(item1);
itemsSet.add(item2);
cart1.setItems(itemsSet); // wrong!
如上所示,item2引用了 cart2,而cart2 沒有引用item2,這很糟糕。
Hibernate 應(yīng)該如何將 item2保存到數(shù)據(jù)庫中?item2外鍵會(huì)引用cart1還是cart2?
我們使用關(guān)系擁有方的想法來解決這種歧義;屬于擁有方的引用優(yōu)先并保存到數(shù)據(jù)庫中。
(2)物品作為擁有方
正如JPA 規(guī)范第 2.9 節(jié)中所述,將多對(duì)一方標(biāo)記為擁有方是一種很好的做法 。
換句話說,我將是擁有方,而Cart是 反方,這正是我們之前所做的。
那么我們是如何做到這一點(diǎn)的呢?
通過在Cart類中包含mappedBy屬性,我們將其標(biāo)記為反面。
同時(shí),我們還對(duì)Item進(jìn)行了注解。帶有@ManyToOne的購物車字段,使 Item 成為擁有方。
回到我們的“不一致”示例,現(xiàn)在 Hibernate 知道item2的引用更重要,并將 item2的引用保存到數(shù)據(jù)庫。
讓我們檢查一下結(jié)果:
item1 ID=1, Foreign Key Cart ID=1
item2 ID=2, Foreign Key Cart ID=2
盡管cart在我們的代碼片段中 引用了item2 ,但 item2 對(duì) cart2的引用保存在數(shù)據(jù)庫中。
(3)購物車作為擁有方
也可以將 一對(duì)多的一方標(biāo)記為擁有方,將 多對(duì)一的一方標(biāo)記為反方。
雖然這不是推薦的做法,但讓我們繼續(xù)嘗試一下。
下面的代碼片段顯示了 一對(duì)多端作為擁有端的實(shí)現(xiàn):
public class ItemOIO {
// ...
@ManyToOne
@JoinColumn(name = "cart_id", insertable = false, updatable = false)
private CartOIO cart;
//..
}
public class CartOIO {
//..
@OneToMany
@JoinColumn(name = "cart_id") // we need to duplicate the physical information
private Set<ItemOIO> items;
//..
}
請(qǐng)注意我們?nèi)绾蝿h除mappedBy元素并將多對(duì)一@JoinColumn 設(shè)置為可插入且可更新為false。
如果我們運(yùn)行相同的代碼,結(jié)果將相反:
item1 ID=1, Foreign Key Cart ID=1
item2 ID=2, Foreign Key Cart ID=1
如上所示,現(xiàn)在item2屬于 購物車。
以上就是關(guān)于“Hibernate一對(duì)多注解”的介紹,大家如果對(duì)此比較感興趣,想了解更多相關(guān)知識(shí),不妨來關(guān)注一下動(dòng)力節(jié)點(diǎn)的Java在線學(xué)習(xí),里面的內(nèi)容從入門到精通,相信對(duì)大家的學(xué)習(xí)一定會(huì)有所幫助的。
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問老師會(huì)電話與您溝通安排學(xué)習(xí)
初級(jí) 202925
初級(jí) 203221
初級(jí) 202629
初級(jí) 203743