1. 程式人生 > >hibernate5(12)註解對映[4]一對一外來鍵關聯

hibernate5(12)註解對映[4]一對一外來鍵關聯

在實際部落格網站中,文章內容的資料量非常多,它會影響我們檢索文章其它資料的時間,如查詢釋出時間、標題、類別的等。這個時候,我們可以嘗試將文章內容存在另一張表中,然後建立起文章——文章內容的一對一對映

一對一關聯有兩種方式,一種是外來鍵關聯,另一種是複合主鍵關聯。

外來鍵關聯

下面我們先看一個一對一單向關聯的例項

/*************關聯關係維護方************/
@Table(name = "t_article")
@Entity
public class Article {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private
Integer id; private String title; @OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval = true,targetEntity = ArticleContent.class) @JoinColumn(name = "article_content_id") private ArticleContent articleContent; //忽略get和set方法 }

下面是我們的文章內容類

@Table(name = "t_article_content"
) @Entity public class ArticleContent { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; @Lob private String content; //忽略get和set方法 }

下面是我們的測試類

public class Test3 {
    private ApplicationContext ac;
    private SessionFactory sessionFactory;
    private
Session session; private Transaction transaction; @BeforeClass//在測試類初始化時呼叫此方法,完成靜態物件的初始化 public static void before(){ } @Before//每一個被註解Test方法在呼叫前都會呼叫此方法一次 public void setup(){//建立針對我們當前測試方法的的會話和事務 ac = new ClassPathXmlApplicationContext("spring-datasource.xml"); sessionFactory = (SessionFactory) ac.getBean("sessionFactory"); session = sessionFactory.openSession(); transaction = session.beginTransaction(); } //測試級聯關係對映註解配置:一對一單向關聯 @Test public void test1(){ //測試級聯新增 Article article = new Article(); article.setTitle("title"); ArticleContent articleContent = new ArticleContent(); articleContent.setContent("content"); article.setArticleContent(articleContent);//建立對映關係 session.save(articleContent); session.save(article); //測試級聯刪除 // Article article = (Article) session.get(Article.class,1); // session.delete(article); @After//每一個被註解Test方法在呼叫後都會呼叫此方法一次 public void teardown(){ if(transaction.isActive()){//如果當前事務尚未提交,則 transaction.commit();//提交事務,主要為了防止在測試中已提交事務,這裡又重複提交 } session.close(); }

呼叫我們的測試方法test1。控制檯列印:
Hibernate: insert into t_article_content (content) values (?)
Hibernate: insert into t_article (article_content_id, title) values (?, ?)
此時檢視資料庫:

mysql> show tables; ————————————hibernate幫我們新建的表格
+———————+
| Tables_in_hibernate |
+———————+
| t_article |
| t_article_content |
+———————+
2 rows in set (0.00 sec)

mysql> desc t_article; ————————————單方維護對映關係,通過article_content_id維護
+——————–+————–+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+——————–+————–+——+—–+———+—————-+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(255) | YES | | NULL | |
| article_content_id | int(11) | YES | MUL | NULL | |
+——————–+————–+——+—–+———+—————-+
3 rows in set (0.00 sec)

mysql> desc t_article_content;
+———+———-+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+———+———-+——+—–+———+—————-+
| id | int(11) | NO | PRI | NULL | auto_increment |
| content | longtext | YES | | NULL | |
+———+———-+——+—–+———+—————-+
2 rows in set (0.00 sec)

mysql> select * from t_article;
+—-+——-+——————–+
| id | title | article_content_id |
+—-+——-+——————–+
| 1 | title | 1 |
+—-+——-+——————–+
1 row in set (0.00 sec)

mysql> select * from t_article_content;
+—-+———+
| id | content |
+—-+———+
| 1 | content |
+—-+———+
1 row in set (0.00 sec)

註釋掉測試程式碼的級聯新增部分,執行級聯刪除部分:

Hibernate: delete from t_article where id=?
Hibernate: delete from t_article_content where id=?
在這裡,我們觀察到它是先刪除文章(維護關係方),再刪除t_article_content的,回想我們之前的一對多關聯測試,都是先刪除維護關係方的,這其實很好理解,我們肯定要清除掉相應的關聯關係(體現在資料庫的外來鍵上)才能完成被關聯內容的刪除操作

一對一雙向關聯很簡單,直接在articleContent上新增:

@OneToOne(cascade = CascadeType.ALL,mapperBy = "articleContent")
private Article article;
//忽略getter/setter

使用和上面一樣的測試程式碼,hibernate會幫我們生成表格並插入資料:

mysql> select * from t_article_content;
+—-+———+
| id | content |
+—-+———+
| 1 | content |
+—-+———+
1 row in set (0.00 sec)

mysql> select * from t_article;
+—-+——-+——————–+
| id | title | article_content_id |
+—-+——-+——————–+
| 1 | title | 1 |
+—-+——-+——————–+
1 row in set (0.00 sec)

這時候如果我們嘗試在放棄維護的articleContent端進行級聯新增:

//測試articleContent級聯新增
Article article = new Article();
article.setTitle("title");
ArticleContent articleContent = new ArticleContent();
articleContent.setContent("content");
articleContent.setArticle(article);
session.save(articleContent);

我們的article物件能被成功儲存,但是,兩者的關聯關係建立失敗:

mysql> select * from t_article_content;
+—-+———+
| id | content |
+—-+———+
| 1 | content |
| 2 | content |
+—-+———+
2 rows in set (0.00 sec)

mysql> select * from t_article;
+—-+——-+——————–+
| id | title | article_content_id |
+—-+——-+——————–+
| 1 | title | 1 |
| 2 | title | NULL |
+—-+——-+——————–+
2 rows in set (0.00 sec)

這時候我們再嘗試從放棄維護端刪除:

//這次刪除是有級聯關係的
ArticleContent articleContent = (ArticleContent) session.get(ArticleContent.class, 1);//注意這裡id為1
session.delete(articleContent);

mysql> select * from t_article_content;
+—-+———+
| id | content |
+—-+———+
| 5 | content |
+—-+———+
1 row in set (0.00 sec)

mysql> select * from t_article;
+—-+——-+——————–+
| id | title | article_content_id |
+—-+——-+——————–+
| 6 | title | NULL |
+—-+——-+——————–+
1 row in set (0.00 sec)

會看到我們相應article物件也被刪除了!因此,我們需要明確放棄維護關聯關係並不代表放棄關聯關係,從ArticleContent端,我們一樣能進行與關聯關係雙管的級聯新增、刪除操作。只是不對兩者關係進行維護,因而在新增時Article端的外來鍵屬性article_content_id=null
我們使用mappedBy屬性放棄關聯,但級聯操作依然有效,因此需要區分開維護關聯關係級聯操作的區別。

這裡需要特別注意的是,在這種一對一對映中,我們最好選擇一個被動方並設定mapperBy屬性,即讓一方放棄維護關聯關係,否則,我們會看到下述現象:
mysql> desc t_article;
+——————–+————–+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+——————–+————–+——+—–+———+—————-+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(255) | YES | | NULL | |
| article_content_id | int(11) | YES | MUL | NULL | |
+——————–+————–+——+—–+———+—————-+
3 rows in set (0.00 sec)

mysql> desc t_article_content;
+————+———-+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+————+———-+——+—–+———+—————-+
| id | int(11) | NO | PRI | NULL | auto_increment |
| content | longtext | YES | | NULL | |
| article_id | int(11) | YES | MUL | NULL | |
+————+———-+——+—–+———+—————-+
3 rows in set (0.00 sec)

兩個表中都建立了關於對方的關聯對映。這是完全沒有必要的,而且這樣會造成的更嚴重後果,我們來測試級聯新增
先呼叫如下測試程式碼:

//測試article級聯新增
Article article = new Article();
article.setTitle("title");
ArticleContent articleContent = new ArticleContent();
articleContent.setContent("content");
article.setArticleContent(articleContent);
session.save(article);

再呼叫如下測試程式碼:

//測試articleContent級聯新增
Article article = new Article();
article.setTitle("title");
ArticleContent articleContent = new ArticleContent();
articleContent.setContent("content");
articleContent.setArticle(article);
session.save(articleContent);

我們會看到資料庫對應記錄:

mysql> select * from t_article;
+—-+——-+——————–+
| id | title | article_content_id |
+—-+——-+——————–+
| 1 | title | 1 |
| 2 | title | NULL |
+—-+——-+——————–+
2 rows in set (0.00 sec)

mysql> select * from t_article_content;
+—-+———+————+
| id | content | article_id |
+—-+———+————+
| 1 | content | NULL |
| 2 | content | 2 |
+—-+———+————+
2 rows in set (0.00 sec)

即雙方各維護各的關聯關係,如果這時候我們嘗試交換測試級聯刪除:

Article article = (Article) session.get(Article.class,2);
session.delete(article);

會看到如下結果:

mysql> select * from t_article;
+—-+——-+——————–+
| id | title | article_content_id |
+—-+——-+——————–+
| 1 | title | 1 |
+—-+——-+——————–+
1 row in set (0.00 sec)

mysql> select * from t_article_content;
+—-+———+————+
| id | content | article_id |
+—-+———+————+
| 1 | content | NULL |
| 2 | content | 2 |
+—-+———+————+
2 rows in set (0.00 sec)

即級聯刪除失敗了,而這是顯然的,因為id為2的文章,對應article_content_id屬性為null,在文章方看來,兩者都沒建立關聯關係,這種時候肯定不是報錯就是級聯刪除失敗,而報錯是因為如果設定了資料庫在t_article_content中設定了對article_id的的外來鍵關聯,因為存在記錄article_id=2,這時候我們嘗試刪除article表中id為2的記錄,則會由於外來鍵關係約束失敗而報錯

相關推薦

hibernate5(12)註解對映[4]一對一外來關聯

在實際部落格網站中,文章內容的資料量非常多,它會影響我們檢索文章其它資料的時間,如查詢釋出時間、標題、類別的等。這個時候,我們可以嘗試將文章內容存在另一張表中,然後建立起文章——文章內容的一對一對映 一對一關聯有兩種方式,一種是外來鍵關聯,另一種是複合主鍵關聯

hibernate5(12)註解映射[4]一對一關聯

rom 成功 查詢 content cat 回憶 target his var 在實際博客站點中,文章內容的數據量非常多,它會影響我們檢索文章其他數據的時間,如查詢公布時間、標題、類別的等。這個時候,我們能夠嘗試將文章內容存在還有一張表中,然後建立起文章

hibernate5(13)註解對映[5]一對一共享主關聯

一對一共享主鍵 下面我們直接通過例項來講解共享主鍵配置: 主鍵主控方:Article package com.zeng2.model; @Table(name = "t_article2")

Hibernate,關係對映的多對一單向關聯、多對一雙向關聯一對一關聯一對一外來關聯、多對多關係關聯

2018-11-10  22:27:02開始寫   下圖內容ORM、Hibernate介紹、hibername.cfg.xml結構:     下圖內容hibernate對映檔案結構介紹   下圖內容hibernate

Hibernate 對映關係 ---One2One 外來關聯

1.One2One 外來鍵單向關聯 是 many-2-one 的特殊案例,在多的一端使用unique =true, 多的一端配置如下: <classname="Person"table="t_person"> <idname="id"column="id

Hibernate ORM對映:基於外來一對一

概念 一一對應關係,要求雙方都有對方的引用。 實現方式 在Department這一端設定many-to-one關聯關係,但同時給關聯到Manager的外來鍵設定唯一約束 建立持久化類

hibernate雙向一對一關聯對映XML與註解

雙向一對一關聯對映原理:  雙向的主鍵關聯其實是單向一對一主鍵關聯的一種特殊情況,只不過要在關聯物件的兩端的對映檔案中都要進行<one-to-one>的配置,另外還要在主對映的主鍵一端採

Hibernate 一對一關聯對映(主關聯VS唯一外來關聯

一對一關聯對映有兩種:一種是主鍵關聯,一種是“唯一”外來鍵關聯。 主鍵關聯:原理是兩張表的主鍵(ID)保持一致,在獲取的時候根據兩種表中的ID相同來作為關係判斷的標準,這樣的設計好處在於我們不用新增另外的欄位來維護它們之間的關係。 廢話少說,看例子。 在生活一對一的關係還“

hibernate註解實現一對一雙向外來關聯

一對一雙向外來鍵關聯1、主控方的配置同一對一單向一樣不用更改2、在被控方設定關聯物件的屬性引用上加上@OneToOne主鍵3、雙向關聯,必須要有mappedBy屬性(mappedBy的意思是由對方主導關聯關係)注意:自動生成表時會在兩張表上都加入外來鍵關聯關係,可以通過沒置m

Hibernate對映詳解--一對一唯一外來關聯對映

  還記得多對一的那個例子嗎?使用者與組。我們在多的一端維護關係,最後生成的表格中,多的一端User中多出來一個欄位groupId用來儲存組的主鍵。這裡,多個使用者可以屬於同一組。即在使用者這個表中,groupId欄位的值是可以重複的。但有的時候可能這個外來鍵值是不可以重複

七、Hibernate對映之放棄外來的維護

什麼是外來鍵維護? 外來鍵維護就是Hibernate操作資料庫的時候會自動更新與之相關聯的表的外來鍵值,而如果放棄外來鍵維護的話,那麼就僅僅是操作表中的資料,不會修改外來鍵值。 什麼時候需要放棄外來鍵維護? 在多對多關係的表中必須要其中一方放棄維護外來鍵,因為維護外來鍵的一方

Spring date jpa onetoone的問題,有關一對一外來的寫法

 最近在寫spring boot專案的時候遇到了有關spring date jpa的一些問題,其中對@OneToOne,一對一外來鍵的設定不怎麼理解,百度了很多都不成功,最後通過查閱資料看到了如何來寫這個一對一的外來鍵,話不多說,直接上程式碼。 package com.b5

hibernate5(15)註解對映[7]集合關聯

集合註解對映 集合關係對映可以看成是一對多關係對映的一種簡化,在一個電商系統裡,出售的產品可能會有多張展示圖片,如果我們使用一對多來建立關聯對映時,需要建立一個實體類Images,裡面可能有屬性:圖片在伺服器的訪問路徑url和圖片所屬產品productId。但

Hibernate一對一關聯(基於annotation註解方式)

 hibernate中一對一的關聯有兩種方式:一種是採用外來鍵關聯,另外一種是採用主鍵關聯。  最近專案中用到一對一主鍵雙向關聯,並且是基於註解的方式。期間遇到一些問題,現在貼出來探討探討。  一個丈夫(husband)對應一個妻子(wife),主要目標是在儲存丈夫或者妻子

Hibernate (八)一對一外來關聯方式)

一對一 對映有兩種方式: 主鍵關聯: id 對應 id 兩個主鍵必須相同 外來鍵關聯: id 對應 xxxid 專門設定一個外來鍵屬性 (推薦使用) 外來鍵關聯方式 例如:下面的例子IdCard 表會有一個專門的外來鍵屬性 personId 對應 pe

hibernate5(11)註解對映[3]一對多多對一雙向關聯

在上兩篇文章裡,我們詳細地分別講解了一對多和多對一的單向關聯配置的具體屬性含義,在這一篇文章裡,我們完成兩者的的整合建立雙向關聯。 在實際的部落格網站中,我們可能需要根據文章讀取作者(使用者)資訊,但肯定也要讓使用者能獲取自己的文章資訊,針對這種需求,我們可以

hibernate5(9)註解對映[1]多對一單向關聯

在部落格網站中,我們可能需要從某一篇文章找到其所關聯的作者,這就需要從文章方建立起對使用者的關聯,即是多對一的對映關係。 現在先看一個配置例項:我們的文章實體類 package com.zeng.model; import javax.persistenc

4.引用外來的優缺點

作用:保持資料的一致性、完整性為何說外來鍵有效能問題:1.資料庫需要維護外來鍵的內部管理;2.外來鍵等於把資料的一致性事務實現,全部交給資料庫伺服器完成;3.有了外來鍵,當做一些涉及外來鍵欄位的增,刪,

mysql清空有外來關聯的表

第一種:(不要外來鍵約束) 手動刪除外來鍵約束; 刪除表資料   第二種:(保留外來鍵約束) SET FOREIGN_KEY_CHECKS = 0;   TRUNCATE TABLE 表名;  SET FOREIGN_KEY_CHECKS = 1; 

MySQL:使用SQL語句清空所有外來關聯

 解決辦法 查詢資料庫中所有外來鍵名稱然後拼接生成刪除語句,再複製執行 SELECT CONCAT('ALTER TABLE ',TABLE_SCHEMA,'.',TABLE_NAME,' DROP FOREIGN KEY ',CONSTRAINT_NAME,' ;') FROM