hibernate5(12)註解映射[4]一對一外部索引鍵關聯

來源:互聯網
上載者:User

標籤:ado   部分   set   _id   context   print   nfa   esc   單向關聯   

在實際部落格網站中,文章內容的資料量非常多,它會影響我們檢索文章其他資料的時間,如查詢公布時間、標題、類別的等。

這個時候,我們能夠嘗試將文章內容存在還有一張表中,然後建立起文章——文章內容的一對一映射

一對一關聯有兩種方式,一種是外部索引鍵關聯。還有一種是複合主鍵關聯。

外部索引鍵關聯

以下我們先看一個一對一單向關聯的執行個體

/*************關聯關係維護方************/@Table(name = "t_article")@Entitypublic 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")@Entitypublic 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的,回憶我們之前的一對多關聯測試。都是先刪除維護關係方的。這事實上非常好理解,我們肯定要清除掉相應的關聯關係(體如今資料庫的外鍵上)才幹完畢被關聯內容的刪除操作

一對一雙向關聯非常easy,直接在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為1session.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]一對一外部索引鍵關聯

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.