1. 程式人生 > >架構小白到磚家-09-資料庫的價值-多表查詢和特殊操作處理

架構小白到磚家-09-資料庫的價值-多表查詢和特殊操作處理

通過前面對jpa提供的JpaRepository和JpaSpecificationExecutor兩種面向物件資料庫操作研究,已經解決了絕大多數開發工作中單表物件化操作。這兩種解決方案確實都非常優雅,省去了寫SQL的煩惱,甚至連線口的實現類都不需要我們去寫了。但是我們心中更加好奇,jpa難得真的就能將資料庫概念給抹殺掉了嗎?讓我們帶著疑問,再繼續整理一下,還有什麼資料庫使用場景咱們沒有討論到。
在這裡插入圖片描述
前面已經提到過,咱們一直討論的單表操作,那麼資料庫的多表查詢呢?我們先來看看jpa怎麼處理多表之間的關聯關係。資料庫理論中有正規化概念,一共定義了六種正規化,有興趣的同學可以自己去補充下這個知識,這裡就不展開討論了。我們可以簡單把正規化理解為將一個複雜資料模型從一張單表,拆解成多張子表的規範。這裡為了討論方便,我們還是舉一個多表模型案例,就使用者許可權模型吧。

使用者許可權我們就簡化成使用者和角色兩個模型,使用者和角色是多對多的雙向關係,這種關係在資料庫正規化中,我們需要建立除了使用者表和角色表之外,還要建立一張使用者角色關係表。那麼在ORM框架方案中,定義了資料庫表關係註解,@OneToOne,@OneToMany,@ManyToMany。由於這個方案的內容非常多,咱們就不展開討論這些註解的使用方法。咱們主要是為了說明解資料庫多表之間關係,通過資料庫正規化的要求,有主外來鍵和關係表的概念,並且ORM框架提供了對映關係的方案。
在這裡插入圖片描述

我們已經定義好了使用者表、角色表、使用者角色關係表,不管是自己建立資料庫表,還是ORM框架自動生成,資料庫的理論都是不會改變的,都會生成這樣三張表。那麼我們在實際的開發過程中,使用的是物件,所以我們還是需要把JAVA的物件模型創建出來,為了簡化討論範圍,我們只研究使用者對角色的一對多單向關係。
在這裡插入圖片描述

咱們的資料庫多表模型案例就準備就緒了,可以進行討論了。User和Role的單表對映,咱們都已經會了,只需要在User中新增一個@OneToMany關係。正常SQL操作來說,查詢使用者資訊,先獲取User資訊,然後在獲取使用者對應的角色資訊放入User物件中roles。就需要傳送兩條SQL,查詢使用者資訊,查詢角色資訊。儲存一個使用者時,也需要兩條SQL,儲存使用者資訊,儲存使用者角色關係資訊。

下面再來給幾個具體案例場景,看看SQL操作和ORM操作都怎麼處理。
第一修改使用者密碼,只需要使用者資訊;
第二獲取選單資訊,需要使用者和角色資訊;
第三刪除使用者資訊。

使用SQL
第一個場景,只查詢使用者一條SQL,
第二個場景,傳送兩條SQL。或者不在乎資料庫效能,第一和第二場景都發送兩條SQL。
第三個場景,先刪除user表資訊,在刪除關係表資訊。或者只刪除使用者表,關係表不刪除。當然這種操作需要降低資料庫正規化要求,關係表不使用強制外來鍵,就只是普通欄位。這種操作雖然不合理,會造成關係表中有髒資料,但是可以快速滿足業務需求,實際場景中經常遇到很多非合理業務要求。

使用ORM框架
第一個場景,可以設定懶載入,進行延遲抓取,發一條SQL;
第二個場景,需要設定立即載入,傳送兩條SQL。如果也是懶載入,就會在使用角色資訊的時候,再發SQL獲取,會引發兩個問題,一個問題是使用角色資訊的時候,超出了事務範圍,無法獲取資料了;另一個問題是造成N+1問題,每一個角色都會發送一條SQL。
第三個場景,只刪除user物件就可以了,會自動刪除關係表資訊。表關係必須是強制外來鍵,這種情況如果是一對一雙向關係,那就麻煩了,刪除一端,必須刪除另外一端,否則無法刪除。非常不靈活,特別是業務模型很複雜,關聯關係很多的情況。
在這裡插入圖片描述
簡單的從上面的對比中可以看出來,使用SQL會更加靈活,限制條件不多,可以降低資料庫正規化等級來滿足複雜多變的業務場景需求;但是ORM方式就必須嚴格遵守資料庫強制外來鍵的正規化等級,理論上正規化等級越高資料庫使用越合理,實際情況並不是這樣,正規化的使用是需要特定業務場景的限制。另外還有資料載入時機問題,懶載入和立即載入只能二選一,引入更多的使用條件限制和N+1的難題。以前有過專案嘗試ORM強制外來鍵關係,最後都是慘痛教訓收場。當然ORM這種方案還是有一定優點,物件化操作多表資料,自動聯動表關係處理,但是也帶來了更多壞處,屬於得不償失的情況。
在這裡插入圖片描述

結論,建議放棄ORM的多表方案,降低資料庫正規化等級,不要使用強制外來鍵,自己手動維護資料庫表關係。但是必須在有清晰的資料庫模型管理制度前提上。

回顧總結,資料儲存方案中,JPA沒法完全消除資料庫概念,需要原生SQL來解決多表查詢和特殊操作處理,比如報表查詢就是一個典型案例,報表涉及到大量的資料庫函式、多表連線、子檢視查詢等複雜SQL;還有一些特殊場景需要使用到資料庫儲存過程,來高效處理批量資料問題。