天天看點

hibernate5(10)注解映射[2]一對多單向關聯

在上一篇文章裡,我們從端方向一端建立關聯關系,完成了從文章到作者的關聯關系建立,但在實際的部落格網站中,使用者肯定還需要擷取自己所寫的文章,這時可以建立使用者(一)對文章(多)的單向關聯映射。

先來看我們的一方配置執行個體

下面是我們對應的多方配置

根據這些配置,我們來編寫測試方法:

執行測試方法,我們會看到控制台列印下列sql語句: hibernate: insert into t_user1 (name) values (?) hibernate: insert into t_article1 (content) values (?) hibernate: insert into t_user1_t_article1 (t_user1_id, articles_id) values (?, ?) 在前四句,我們看到在儲存user對象時,級聯儲存了我們的文章對象,最後面三條資訊又是什麼?原來在我們沒有設定@joincolumn(具體使用方法請參考我的上篇文章)。那麼在一對多的關聯配置中,hibernate會預設幫我們生成中間表來完成兩者的映射關系,查詢資料庫,我們會發現 mysql> select * from t_user1_t_article1; +————+————-+ | t_user1_id | articles_id | | 1 | 1 | | 1 | 2 | | 1 | 3 | 3 rows in set (0.00 sec) 确實是通過中間表,将使用者和文章關聯起來了。 這時進行級聯删除測試: “`java user user = (user) session.get(user.class, 1); session.delete(user);

修改對應表名,讓hibernate重新在資料庫中生成表,此時再運作我們的測試方法,會看到:

hibernate: insert into t_user2 (name) values (?)

hibernate: insert into t_article2 (content) values (?)

hibernate: insert into t_article2 (content) values

hibernate: update t_article2 set user_id=? where id=?

此時我們會看到,最後三行換成了更新我們的表屬性值。從這裡我們看出為了更新aritlce表中user_id對應值,我們額外使用多了三條資料,這是很不值的,會額外消耗資料庫的性能,有沒方法使得在插入文章表的同時插入user_id的值呢?檢視hibernate源碼,我們會發現這是因為user作為主動方,它處理關聯對象時必須通過update來完成,如果我們想取消update,應該将user放棄主動,讓另一方(多方)去維護,這又涉及到我們的一對多、多對一雙向關聯了,我們在下一篇文章再具體解決這一問題。

這個時候我們來測試級聯删除:

會得到如下列印資訊: hibernate: update t_article2 set user_id=null where user_id=? hibernate: delete from t_article2 where id=? hibernate: delete from t_user2 where id=? 注意到,它的删除順序是:清除使用者表和文章表的關聯關系(這又是因為使用者表作為主動方,它必須通過此方法來維護關聯關系->然後清除多方文章資訊->最後才删除我們的一方使用者

上面我們基本完成了我們的測試工作,下面我們對配置屬性加以分析:

1. 相對于上一篇我們提到的manytoone屬性,onetomany獨有的屬性有:mapperby和orphanremoval,mpperby是指放棄維護級聯關系,具體我們在雙向關聯中再詳細分析,這裡比較獨特的屬性是orphanremoval

表面意思是去除孤兒,當一方不再關聯多方某一實體a時,自動從資料庫中删除a。下面來看執行個體測試,假如我們先将其設為false

先看看我們資料庫的初始記錄資訊:

+—-+———–+ | id | name | | 2 | oneobject | 1 row in set (0.00 sec) mysql> select * from t_article2; +—-+————–+———+ | id | content | user_id | | 6 | morecontent0 | 2 | | 5 | morecontent1 | 2 | | 4 | morecontent2 | 2 |

接着開始我們的測試:

運作測試代碼,我們會看到控制台僅輸出一條sql語句:

hibernate: update t_article2 set user_id=null where user_id=? and id=?

查詢資料庫,此時變成:

| 4 | morecontent2 | null |

現在我們先恢複測試前的資料:

<code>mysql&gt; update t_article2 set user_id = 2 where id = 4;</code>

然後再将對應注解裡的orphanremoval設為true

再次運作我們的測試代碼,控制台輸出:

我們的文章記錄就對應被删除了,這就是去除“孤兒”的含義,在實際開發中,正如我們的身份證總是從屬于某個人的,如果失去這種從屬關系,身份證就沒有意義而可以去除了。

在預設不使用@joincolumn時,多對一關聯中hibernate會為我們自動生成中間表,但如果我們像自己來配置中間表,就可以使用@jointable注解。它的執行個體配置如下:

其中:

1. name為建立的中間表名稱。

2. inversejoincolumns指向對方的表,在這裡指多方的表。

3. joincolumns指向自己的表,即一方的表,這些指向都是通過主鍵映射來完成的。

運作我們的測試代碼:

會發現我們的使用者、文章對應關系都在中間表中建立起來了:

mysql&gt; select * from t_user_articles; +———+————+ | user_id | article_id | | 1 | 1 | | 1 | 2 | | 1 | 3 | 使用中間表的好處是對原來兩張表的結構不對造成任何影響。尤其是在一些老項目中我們可以不修改既定的表結構(事實上在一個項目古老龐大到一定程度就很難去改)、以不侵入原來表的方式建構出一種更清淅更易管理的關系。當然缺點是我們的我們需要維護多一張表,一旦中間表多了,維護起來會愈加麻煩。但綜合來看,我們顯然更推薦用中間表的方式來完成配置。

在我們開始配置一對多的一方時,我們通過set來和多方建立關系,其中提到的一點是可以防止多方相同對象出現。這個相同對應我們資料庫中就是某些屬性列相同,比如:對于article,如果id和content在兩條記錄中都一樣,我們就可以認為兩條記錄是一緻的,是以會自動去重那麼我們來判斷它們的重複關系呢?這個時候就要通過重寫hashcode和equals方法了。

示例如下:

一般來說,我們重寫equal方法就能判斷兩個對象是否相等了,為什麼還要重寫hashcode方法呢?主要是考慮到效率的問題,對于equals方法,當比較規則比較複雜的話就會比較耗時了,而hashcode為每一個對象生成一個散列碼(通過一種神秘的算法,一般為關鍵屬性乘以一個質數),避免了比較慢的運算。不過我們不能因為快就單憑hash碼來判斷兩個對象是否相等,因為hashcode并不能保證能為每一個不同的對象生成唯一的散列碼,是以可能會有兩個hash碼相同,但對象确實不一緻的情況。不過我們知道的是如果連hash碼都不一緻,那兩個對象肯定是不一緻的。根據此思路,我們可以很好地了解在java内部,是如何判斷兩個對象是否相等的:

hibernate5(10)注解映射[2]一對多單向關聯
上一篇: 讀書累不累
下一篇: linux學習