特征阻抗和阻抗匹配_没有诸如对象关系阻抗不匹配之类的东西
特征阻抗和阻抗匹配
過去十年來,ORM的許多批評都錯了這一點,因為它不準確。 到本文結尾,我們將得出以下結論:
關系(數據)模型和面向對象的模型之間沒有顯著差異
如何得出這個結論? 繼續閱讀!
我們如何相信這種謬論
許多流行的博客作者和意見領袖都沒有機會抨擊ORM,因為它們與關系世界的“明顯”阻抗不匹配。 N + 1 , 效率低下的查詢 , 庫的復雜性 , 抽象的泄漏 ,各種流行語已被用來消除ORM,盡管沒有提供可行的替代方案,但它們通常包含很多真相。
但是這些文章是否真的在批評正確的事情?
上面的文章中很少有人會認識到一個中心事實,這是Erik Meijer和Gavin Bierman在其非常有趣的論文“ 大型共享數據銀行的數據的關聯模型 ”中雄辯地幽默地提出的:
與流行的看法相反,SQL和noSQL實際上只是同一枚硬幣的兩個方面。
換句話說:“分層”對象世界和“關系”數據庫世界為完全相同的事物建模。 唯一的區別是在圖中繪制箭頭的方向。
讓它沉入。
- 在關系模型中,孩子指向父母。
- 在分層模型中,父母指向孩子。
這里的所有都是它的。
什么是ORM?
ORM填補了兩個世界之間的橋梁。 如果您愿意,它們就是箭頭的逆變器 。 他們將確保RDBMS中的每個“關系”都可以在“分層”世界中實現為“聚合”或“組合”(這適用于對象,XML,JSON和任何其他格式)。 他們確保正確實現此類實現。 可以正確地跟蹤對單個屬性或關系(聚合,組成)屬性所做的更改,并將其清除回持久模型的主模型數據庫中。 各個ORM 除了將各個實體映射到各個類型之外 ,在提供的功能以及它們提供多少映射邏輯方面也有所不同。
- 一些ORM可能會幫助您實現鎖定
- 有些可以幫助您修補模型不匹配的問題
- 有些人可能只專注于這些類和表之間的1:1映射
但是所有ORM都做一件非常簡單的事情。 最終,它們從表中獲取行,并將其具體化為類模型中的對象,反之亦然。
順便說一下,最近在Vertabelo博客上對不同的ORM進行了很好的概述 。
表和類是同一回事
給出或采用1-2個實現細節,RDBMS的表和OO語言的類是同一回事。 一組分組屬性的規范,每個屬性及其關聯的類型。 考慮以下使用SQL和Java的示例:
SQL
CREATE TABLE author (first_name VARCHAR(50),last_name VARCHAR(50) );Java
class Author {String firstName;String lastName; }兩者之間絕對沒有概念上的區別-映射很簡單。 當您考慮不同實體/類型之間的“關系” /“組成”時,映射甚至非常簡單:
SQL(為簡單起見,我們省略了約束)
CREATE TABLE author (id BIGINT,first_name VARCHAR(50),last_name VARCHAR(50) );CREATE TABLE book (id BIGINT,author_id BIGINT,title VARCHAR(50), );Java
class Author {Long id;String firstName;String lastName;Set<Book> books; }class Book {Long id;Author author;String title; }省略了實現細節(可能占批評的一半)。 但是,由于省略了更多細節,因此可以將數據庫中的各個行直接進行1:1映射,而不會感到驚訝。 大多數ORM(尤其是在Java生態系統Hibernate中)已經很好地實現了上述想法,而隱藏了在RDBMS和Java之間實際進行這種模型轉換的所有技術細節。
換一種說法:
這種映射方法絕對沒有錯!
然而:某處存在* IS *阻抗不匹配
許多博客作者批評的“問題”并非源于兩種模型表示形式之間不存在的不匹配(“關系”與“分層”)。 問題來自SQL,它是關系代數的一種不錯的實現。
實際上,在以下情況之間也存在著每個人都批評的不匹配現象:
- 關系模型
- 關系代數
已經定義了關系代數,以便能夠查詢關系并形成新的特殊關系作為此類查詢的輸出。 根據所應用的操作和轉換,結果元組可能與查詢中涉及的各個實體完全無關 。 換句話說,關系代數,尤其是SQL的乘積沒有用,因為ORM不再可以對其進行進一步處理,更不用說將其持久化回到數據庫了。
為了使事情變得“更糟”,如今SQL是關系代數所提供功能的大型超集。 它比起初設想時有用得多。
為什么這種不匹配仍然會影響現代ORM
前面的段落概述了ORM受到真正批評的唯一主要原因,即使此類批評通常沒有提及確切原因:
SQL /關系代數并不是真正適合將關系部分實現到客戶端/將更改存儲回數據庫。 但是,大多數RDBMS只能為該工作提供SQL。
回到作者/書籍示例。 當您想要將作者及其書籍加載并顯示給Web應用程序的用戶時,您只想簡單地獲取該作者及其書籍,就可以調用諸如author.add(book)以及author.remove(book)類的簡單方法。然后讓魔術將您的數據刷新回存儲系統。
考慮為這樣一個簡單的CRUD任務編寫SQL代碼量會讓每個人尖叫。
人生苦短,無法花時間去CRUD
也許QUEL對于CRUD可能是更好的語言 ,但是那艘船已經航行了。 不幸的是,由于SQL是不適合該工作的語言,您不能忽略這種“魔術”,而必須充分了解幕后發生的事情,例如通過調整Hibernate的獲取策略 。
轉換為SQL后,可以通過幾種方式實現:
1.使用JOIN獲取
使用外部聯接,可以一次性查詢所有涉及的實體:
SELECT author.*, book.* FROM author LEFT JOIN book ON author.id = book.author_id WHERE author.id = ?優點:
- 可以發出單個查詢,并且可以一次傳輸所有數據
缺點:
- 作者屬性在每個元組中重復。 客戶端(ORM)必須先刪除作者的重復數據,然后再填充作者與書籍的關系。 當您有多個嵌套關系應立即獲取時,這可能特別糟糕。
2.使用SELECT獲取
為每個實體發出一個查詢:
SELECT * FROM author WHERE id = ?SELECT * FROM book WHERE author_id = ?優點:
- 要傳輸的數據量很小:每行僅傳輸一次。
缺點:
- 發出的查詢數量可能會爆發成眾所周知的N + 1問題 。
Hibernate尤其了解其他類型的獲取策略,盡管它們本質上是上述方法之一的變體/優化。
為什么不使用SQL MULTISET?
在這種情況下,使用高級SQL來獲取所有數據的理想方法是使用MULTISET :
SELECT author.*, MULTISET (SELECT book.*FROM bookWHERE book.author_id = author.id ) AS books FROM author WHERE id = ?上面的代碼實際上將為每個作者創建一個嵌套的集合:
first_name last_name books (nested collection) --------------------------------------------------Leonard Cohen title--------------------------Book of MercyStranger MusicBook of LongingErnest Hemingway title--------------------------For Whom the Bell TollsThe Old Man and the Sea如果添加另一個嵌套實體,則很容易看到另一個MULTISET如何允許附加嵌套數據:
SELECT author.*, MULTISET (SELECT book.*, MULTISET (SELECT c.*FROM language AS tJOIN book_language AS blON c.id = bc.language_idAND book.id = bc.book_id) AS languagesFROM bookWHERE book.author_id = author.id ) AS books FROM author WHERE id = ?現在的結果是:
first_name last_name books -----------------------------------------------------Leonard Cohen title languages-----------------------------Book of Mercy language------------enStranger Music language------------endeBook of Longing language------------enfres優點:
- 單個查詢可以以最小的帶寬使用來實現所有渴望加載的行。
缺點:
- 沒有。
不幸的是,RDBMS對MULTISET的支持很差。
MULTISET SQL:2003起 , MULTISET (以及數組和其他集合類型)已正式引入SQL標準中,這是將OO功能嵌入SQL語言的一項舉措。 例如,Oracle已經實現了大部分功能,就像Informix一樣,或者鮮為人知的CUBRID(盡管使用了特定于供應商的語法) 。
其他數據庫(例如PostgreSQL)允許將嵌套的行聚合到類型化數組中 ,盡管需要更多的語法工作,但其工作方式相同。
MULTISET和其他ORDBMS SQL功能是完美的折衷方案,可以將“關系”模型的MULTISET與“分層”模型的MULTISET相結合。 允許一次性將CRUD操作與查詢結合在一起,無需復雜的ORM,因為SQL語言可以直接用于將所有數據從(關系)數據庫映射到(分層)客戶端表示形式,而不會產生摩擦。
結論并號召行動!
我們正在行業中度過激動人心的時代。 房間里的大象(SQL)仍然在這里 , 一直在學習新的技巧。 關系模型為我們提供了很好的服務,并且在各種實現中都豐富了分層模型。 函數式編程越來越受關注,以非常有用的方式補充了面向對象的功能。
想一想膠水,將所有這些偉大的技術概念放在一起,就可以:
- 在關系模型中存儲數據
- 在分層模型中實現數據
- 使用功能編程處理數據
如此出色的技術組合很難被擊敗- 我們已經展示了SQL和函數式編程如何與jOOQ一起使用 。 我們認為,所缺少的只是更好地支持RDBMS供應商提供的MULTISET和其他ORDBMS功能。
因此,我們敦促PostgreSQL開發人員:您正在創建最創新的數據庫之一。 Oracle在該領域領先于您-但它們的實現與PL / SQL緊密聯系在一起,這使其笨拙。 但是,您錯過了最出色SQL功能集之一。 構造嵌套集合(不僅是數組)并有效查詢它們的能力。 如果您帶路,其他RDBMS也將隨之而來。
我們終于可以停止浪費時間談論對象關系阻抗非匹配問題。
翻譯自: https://www.javacodegeeks.com/2015/08/there-is-no-such-thing-as-object-relational-impedance-mismatch.html
特征阻抗和阻抗匹配
總結
以上是生活随笔為你收集整理的特征阻抗和阻抗匹配_没有诸如对象关系阻抗不匹配之类的东西的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机网络的核心技术,计算机网络技术的核
- 下一篇: 读论文——“时间序列预测方法综述”