ORM問題域

ORM問題域 - 切爾斯基 - 博客頻道 - CSDN.NET http://blog.csdn.net/chelsea/article/details/5094652

假設(shè)我們必須處理對象的存儲, 加載, 和查詢. 性能和引用完整性的約束, 給接口的實現(xiàn)帶來了以下問題:

加載根對象時如何避免加載大半個數(shù)據(jù)庫

存儲時如何更新整個對象圖

存儲時如何高效的更新整個對象圖

何時同步對象的內(nèi)存狀態(tài)和持久存儲狀態(tài)

如何確保在出錯時保持對象內(nèi)存狀態(tài)和持久存儲狀態(tài)之間的一致性

如何保證引用的唯一性以避免可能的更新沖突

對性能的精益求精, 又促使人們解決更多的細(xì)節(jié)問題:

N+1查詢問題

分離查詢模型和存儲模型

盡量減少查詢語句

這些問題的解決方案又會帶來新的問題.

  1. 加載根對象時如何避免加載大半個數(shù)據(jù)庫

更多的時候這是一個建模問題, 為什么我只需要顯示一點信息, 更新一點信息, 卻拉家?guī)Э诎寻藯U子打不著的親戚都帶上 : 細(xì)粒度對象設(shè)計, 直接訪問需要的信息, 減少所謂根對象的存在

一個workaround是延遲加載, 當(dāng)你無法修復(fù)你錯誤的建模時, 當(dāng)真正去訪問子對象的時候再發(fā)出查詢語句去加載. 這個方案會帶來如下問題:

查詢語句較多. 無解, 延遲意味著至少兩條SQL語句, 只能盡量減少

延遲加載的時機, 是自動透明的延遲加載, 還是用戶確定何時加載

Hibernate可通過配置文件指定是否lazy load, 一旦指定, 后面的load就是透明的在訪問子對象時發(fā)生. 也可在發(fā)出每次查詢時顯式指定

Entity Framework則要求用戶在每一次查詢時顯式指定包含哪個子對象, 對沒有指定包含的子對象, 只能在訪問前顯示使用load(). 理由是決定加載不加載,何時加載都是程序員的責(zé)任

然而更大的問題是如何管理數(shù)據(jù)庫連接, 要確保延遲加載的時候數(shù)據(jù)庫連接是開著的

可以使用Interceptor等技術(shù)維持 Session per request, Open Session in View pattern(處理好異常等, 確保session會關(guān)閉).

能在一個 Session 中使用兩個事務(wù)嗎?

是的冬耿,這事實上是這種模式(Open Session In View)的一個更好的實現(xiàn)个绍。在一個請求事件中船侧,一個數(shù)據(jù)庫事務(wù)用于數(shù)據(jù)的讀寫。第二個數(shù)據(jù)庫事務(wù)僅用于在渲染視圖期間讀數(shù)據(jù)。在這點上沒有對對象的修改。因此,數(shù)據(jù)庫鎖早在第一個事務(wù)時就被釋放了对竣,這使得應(yīng)用有更好的可伸縮性,第二個事務(wù)可以被優(yōu)化榜配。要使用兩階段的事務(wù)否纬,你需要比 Servlet Filter 更強大的攔截器 - AOP 是個很好的選擇。JBoss Seam 使用了這種模式蛋褥。

為什么 Hibernate 不在需要時就加載 Object临燃?

每個月很多人都會有這種想法,為什么 Hibernate 不能在有需要的就開啟一個新的數(shù)據(jù)庫連接(更有效率的是開啟一個 Session)壁拉,然后加載集合或是初始化代理谬俄,而是選擇拋出一個 LazyInitializationException。當(dāng)然弃理,這種想法溃论,第一眼看上去可能是明智之舉。但這種做法有很多的缺點痘昌,只有當(dāng)你考慮特別的事務(wù)訪問時才會發(fā)現(xiàn)钥勋。

如果 Hibernate 可以進(jìn)行任意的數(shù)據(jù)庫連接和事務(wù),這種操作是開發(fā)人員不可知辆苔,并且也是在任何事務(wù)邊界之外的算灸,那還要事務(wù)邊界做什么。當(dāng) Hibernate 開啟了新的數(shù)據(jù)庫連接去加載集合驻啤,但同時集合的擁有者卻被刪除了菲驴,這是將會發(fā)生什么?(注意骑冗,這種情況是不會發(fā)生在上面提到的兩階段的事務(wù)模式中的 - 單個 Session 可對實體可重復(fù)讀赊瞬。)當(dāng)所有的對象都可以通過關(guān)聯(lián)導(dǎo)航獲取時為什么還要有 Service 層?這種方式將消耗多少內(nèi)存贼涩?哪些對象要首先被清除掉巧涧?所有這些問題都是無解的,因為 Hibernate 是一個在線的事務(wù)處理服務(wù)(并包含一些批處理操作)遥倦,并不是一個“在未定義的工作單元中從數(shù)據(jù)持久倉庫取得對象”的服務(wù)谤绳。此外,對于 n+1 查詢問題,我們是否需要 n+1 的事務(wù)和連接的問題缩筛?

這個問題的解決方案當(dāng)然是正確的工作單元劃分和設(shè)計消略,支撐其的攔截技術(shù)就像這里所展現(xiàn)的一樣,并且/或者正確的抓取技術(shù)歪脏,使得特定工作單元所需的全部信息能夠以最小的影響疑俭、最好的性能和伸縮性被獲得。

  1. 存儲時如何更新整個對象圖

框架支持級聯(lián)更新. 是否應(yīng)該級聯(lián)更新, 哪些操作可以級聯(lián), 哪些不可以, 對象之間的哪些類型的關(guān)聯(lián)可以級聯(lián), 哪些不可以, 則是程序員的責(zé)任

通常被聚合的對象, 其生命周期應(yīng)由父對象負(fù)責(zé), 新增/更新/刪除都應(yīng)級聯(lián)

自身有存在意義的實體, 可以級聯(lián)更新, 但不應(yīng)刪除和新增

  1. 存儲時如何高效的更新整個對象圖

常用工作單元模式, Unit of Work.

  1. 何時同步對象的內(nèi)存狀態(tài)和持久存儲狀態(tài)

任何改動都立即提交到數(shù)據(jù)庫會帶來額外開銷. 一個時機是事務(wù)提交時.

Hibernate: 每間隔一段時間婿失,Session會執(zhí)行一些必需的SQL語句來把內(nèi)存中的對象的狀態(tài)同步到JDBC連接中。這個過程被稱為刷出(flush)啄寡,默認(rèn)會在下面的時間點執(zhí)行:

在某些查詢執(zhí)行之前

在調(diào)用org.hibernate.Transaction.commit()的時候

在調(diào)用Session.flush()的時候

  1. 如何確保在出錯時保持對象內(nèi)存狀態(tài)和持久存儲狀態(tài)之間的一致性

數(shù)據(jù)庫事務(wù)回滾, 清空內(nèi)存緩存, 重新加載

  1. 如何避免或處理可能的更新沖突

保證引用的唯一性: 使用單一的加載入口和緩存, Identity Map .

樂觀離線鎖會引入更新沖突問題, 一般使用Versioning來解決, 類似版本控制系統(tǒng)的更新問題; 但業(yè)務(wù)對象很少能自動Merge, Merge的語義也不好定義, 所以一般檢測到?jīng)_突之后只好重做了, 或者取決于業(yè)務(wù)邏輯, Last Win也是一種策略.

  1. N+1查詢問題

Eager Load + JOIN

截然不同的一種避免N+1次查詢的方法是豪硅,使用二級緩存。

N + 1 是關(guān)聯(lián)引入的問題, 網(wǎng)上的解釋和例子傾向于拿one-2-many說事, 但實際上one-2-one依然面臨使用多于一條SQL語句加載的問題

  1. 分離查詢模型和存儲模型

適合業(yè)務(wù)關(guān)系的對象模型未必對查詢是高效的. 需要單獨針對查詢建模, 可以用單獨的索引表來實現(xiàn). 在更新業(yè)務(wù)對象的存儲時同時更新索引表

  1. 盡量減少查詢語句

比如join over multiple select, 比如批量抓取

  1. 值類型

不需要有ID, 通常被聚合. 有對應(yīng)的Class, 但一般沒有對應(yīng)的Table, 僅是Table中的幾個字段

挑戰(zhàn)在于將對象語言類型系統(tǒng)(和開發(fā)者定義的實體和值類型)映射到 SQL/數(shù)據(jù)庫類型系統(tǒng)挺物。 Hibernate: 提供了連接兩個系統(tǒng)之間的橋梁:對于實體類型懒浮,我們使用class, subclass 等等。對于值類型识藤,我們使用 property, component 及其他砚著,通常跟隨著type屬性。這個屬性的值是Hibernate 的映射類型的名字

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痴昧,一起剝皮案震驚了整個濱河市稽穆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赶撰,老刑警劉巖舌镶,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異豪娜,居然都是意外死亡餐胀,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門瘤载,熙熙樓的掌柜王于貴愁眉苦臉地迎上來否灾,“玉大人,你說我怎么就攤上這事鸣奔∧迹” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵溃蔫,是天一觀的道長健提。 經(jīng)常有香客問我,道長伟叛,這世上最難降的妖魔是什么私痹? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上紊遵,老公的妹妹穿的比我還像新娘账千。我一直安慰自己,他們只是感情好暗膜,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布匀奏。 她就那樣靜靜地躺著,像睡著了一般学搜。 火紅的嫁衣襯著肌膚如雪娃善。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天瑞佩,我揣著相機與錄音聚磺,去河邊找鬼。 笑死炬丸,一個胖子當(dāng)著我的面吹牛瘫寝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播稠炬,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼焕阿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了首启?” 一聲冷哼從身側(cè)響起暮屡,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎闽坡,沒想到半個月后栽惶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡疾嗅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年外厂,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片代承。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡汁蝶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出论悴,到底是詐尸還是另有隱情掖棉,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布膀估,位于F島的核電站幔亥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏察纯。R本人自食惡果不足惜帕棉,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一针肥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧香伴,春花似錦慰枕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至低斋,卻和暖如春蜂厅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背膊畴。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工葛峻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人巴比。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像礁遵,于是被迫代替她去往敵國和親轻绞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容