ORM是明顯的反模式
ORM是如何工作的
物件關聯式資料庫ORM技術或模式是使用物件導向技術如Java訪問一個關聯式資料庫,每個語言都有ORM實現,如Java的Hibernate,Ruby的active record, PHP的Doctrine, Python的 SQLAlchemy,在java中,ORM甚至被設計為標準,如JPA。
首先,讓我們看看ORM是如何工作的,。 讓我們使用Java,PostgreSQL,Hibernate。 假設我們有一個表在資料庫中,稱為post :
+-----+------------+--------------------------+ | id | date | title | +-----+------------+--------------------------+ | 9 | 10/24/2014 | How to cook a sandwich | | 13 | 11/03/2014 | My favorite movies | | 27 | 11/17/2014 | How much I love my job | +-----+------------+--------------------------+ <p class="indent"> |
現在,我們需要為這個表產生Java應用的CRUD方式(增刪改查),首先,我們曾經一個Post類:
@Entity @Table(name = "post") public class Post { private int id; private Date date; private String title; @Id @GeneratedValue public int get[author]Id[/author]() { return this.id; } @Temporal(TemporalType.TIMESTAMP) public Date getDate() { return this.date; } public Title getTitle() { return this.title; } public void setDate(Date when) { this.date = when; } public void setTitle(String txt) { this.title = txt; } } <p class="indent"> |
在使用Hibernate操作之前,我們得建立一個session工廠:
SessionFactory factory = new AnnotationConfiguration() .configure() .addAnnotatedClass(Post.class) .buildSessionFactory(); <p class="indent"> |
工廠每次我們要使用Post物件時產生一個session,每次使用session應當如下使用程式碼包裝:
Session session = factory.openSession(); try { Transaction txn = session.beginTransaction(); // your manipulations with the ORM, see below txn.commit(); } catch (HibernateException ex) { txn.rollback(); } finally { session.close(); } <p class="indent"> |
當session準備好後,下面我們就可以從資料表中獲取所有的post:
List posts = session.createQuery("FROM Post").list(); for (Post post : (List<Post>) posts){ System.out.println("Title: " + post.getTitle()); } <p class="indent"> |
我認為這是清楚的, Hibernate是一個強大的連線到資料庫的引擎,透過執行必要的SQL SELECT請求,獲取檢索資料。 然後它建立了類Post的例項,並將資料裝入其中。 當這個物件過來時,它填滿了資料,我們應該使用getter方法將這些資料取出,比如我們使用 getTitle() 方法。
當我們想做一個反向操作,將一個物件傳送到資料庫,我們做的都基本相同,只不過以相反的順序。 我們建立類Post的一個例項 文章,然後塞進入資料,請求Hibernate儲存它:
Post post = new Post(); post.setDate(new Date()); post.setTitle("How to cook an omelette"); session.save(post); <p class="indent"> |
這是幾乎是每一個ORM工作原理。 基本原則始終是相同的——ORM裝有資料的貧血物件。 我們談論的是ORM框架,這些框架與資料庫互動, 物件只有幫助我們將請求傳送給ORM框架,並理解其響應。 除了getter和setter,物件沒有其他方法。 他們甚至不知道他們來自哪個資料庫。
這是物件關係對映是如何工作的。
也許你會問,怎麼了?
ORM怎麼了?
說真的,有什麼錯嗎? Hibernate是最流行的Java庫,已經超過10年了。 世界上幾乎每一個SQL-intensive應用程式都是使用它。 每個Java教程會提及Hibernate(或者 其他一些ORM 像TopLink或OpenJPA)用於database-connected應用程式。 它實際上是一個標準, 然而我還要說它錯了? 是的。
我聲稱整個ORM背後的想法是錯誤的。 它的發明是也許OOP領域空引用之後第二大錯誤 。
其實,我不是唯一一個說這樣的事情的人,絕對不是第一個。 很多非常受人尊敬的作者已經發表關於這個主題,包括 Matinfowler的OrmHate , Jeff Atwood的物件關係對映是電腦科學的越南戰爭 ,Ted Neward的電腦科學的越南 , Laurie Voss的ORM是一種反模式,等等還有許多其他人。
然而我的觀點不同於他們所說的,儘管他們的理由是來自實踐且有效,如ORM是慢的,資料庫升級很難等,他們錯失了主要點,你能從Bozhidar Bozhanov的ORM Haters Don’t Get It文章中看到非常好的實戰回答。
ORM主要點並不是封裝資料庫互動到一個物件,釋放資料,遍歷時撕開了堅固且聚合的living organism(實體),物件的一部分保持資料,而另外一部分是在ORM引擎(session factory)內部執行,這些引擎知道如何處理這些資料,並且轉換它到關聯式資料庫,看看這張圖,它模擬了ORM如何工作:
[img index=1]
我作為Post文章的讀者,得和兩個元件打交道,1是ORM,2是返回一個砍了頭的物件,我打交道的行為應該有一個單點(操作一個元件),這個物件才是OOP,而在ORM這種情況下,我得與兩個點打交道,ORM和資料物件,甚至我們都不能稱之為物件。
因為這個可怕的和明顯地違反了物件導向正規化,我們已經有很多實際中受人尊敬的出版物都在提到這個問題,這裡舉例一些:
SQL並沒有隱藏,ORM的使用者應該會使用SQL(或者方言如HQL),看看上面案例,我們呼叫session.createQuery("FROM Post")是為了獲得所有文章Posts,即使它不是SQL,也很型別,關係模型並沒有被封裝到物件中,相反,它暴露在整個應用程式中,使用這個物件的每個人都必須與關聯式資料庫打交道,以獲得或儲存什麼,這樣ORM並沒有隱藏和封裝SQL,而是汙染了整個應用程式。
難以測試。當一些物件要與Posts文章列表互動時,它需要處理一個例項 SessionFactory 。 我們如何在測試中模擬這種依賴性? 我們必須建立一個它的模擬嗎? 這個任務有多複雜? 看看上面的程式碼,你將意識到冗長和繁瑣的單元測試。 相反,我們可以編寫整合測試並將整個應用程式連線到一個測試版本的PostgreSQL。 在這種情況下,沒有必要模擬一個 SessionFactory ,但這種測試將會相當緩慢,更重要的是,我們卻將一個並沒有和資料庫有關係的資料物件卻作為資料庫的例項物件進行測試。非常糟糕的設計。
我要再次重申。 上面ORM問題導致的後果。 ORM基本缺點是撕裂了物件,可怕和明顯違反了物件理念:一個物件是什麼。
待續見下貼:
[該貼被banq於2014-12-02 11:55修改過]
相關文章
- ORM 是一種討厭的反模式ORM模式
- OpenSessionInView是反模式SessionView模式
- Knative是FaaS的反模式嗎?模式
- Optional.isPresent()是反模式的用法 - stephan模式
- Java的Void方法是反模式的? - DZoneJava模式
- 實體服務是一種反模式模式
- 聊聊jQuery的反模式jQuery模式
- Vim反模式模式
- 泛型方法的反模式泛型模式
- [譯] JavaScript 的函數語言程式設計是一種反模式JavaScript函數程式設計模式
- python 反模式Python模式
- 異常處理的反模式模式
- Unity單例模式,但是是取自Ultrakill反編譯程式碼Unity單例模式編譯
- Prisma是Node.js與TypeScript的ORM框架Node.jsTypeScriptORM框架
- Spring WebFlux的明顯陷阱 - ŁukaszKyćSpringWebUX
- 反直覺SQL舉例說明SQL
- 微軟Chromium版Edge瀏覽器隱私模式新增標識:暗黑模式明顯標識提醒微軟瀏覽器模式
- [BUG反饋]onethink搭建到伺服器後樣式顯示是好是壞伺服器
- 程式設計師的那些反模式程式設計師模式
- Java中的常量:如何避免反模式Java模式
- Redis ORM是一個可怕的主意嗎? -DEV社群RedisORMdev
- 希爾頓&尼爾森:中國遊客消費模式明顯變化模式
- 倉儲模式到底是不是反模式?模式
- Spotify模型的統一運維開發者門戶Backstage是一種反模式 - lastweekinaws模型運維模式AST
- 標籤的顯示模式模式
- 顯示卡的作用和功能介紹 集顯核顯獨顯區別說明
- 自研ORM框架實現工作單元模式ORM框架模式
- Go Web 應用中常見的反模式GoWeb模式
- React 中 getDerivedStateFromProps 的用法和反模式React模式
- Python程式設計中的反模式Python程式設計模式
- 7種微服務反模式微服務模式
- 異常處理反模式模式
- 反DDD模式之“複用”模式
- OpenAI宮鬥反轉反轉再反轉,到底是資本任性還是人性扭曲?OpenAI
- python是誰發明的Python
- 這是我自己的發明
- 服務設計的原則:服務模式與反模式模式
- 不熟悉業務可能是部分資料治理相關廠商的明顯短板