持久化

持久化

持久化是將程序數據在持久狀態和瞬時狀態間轉換的機制。通俗的講,就是瞬時數據(比如內存中的數據,是不能永久保存的)持久化為持久數據(比如持久化至資料庫中,能夠長久保存)。

定義


持久化(Persistence),即把數據(如內存中的對象)保存到可永久保存的存儲設備中(如磁碟)。持久化的主要應用是將內存中的對象存儲在資料庫中,或者存儲在磁碟文件中、XML數據文件中等等。
持久化是將程序數據在持久狀態和瞬時狀態間轉換的機制。
JDBC就是一種持久化機制。文件IO也是一種持久化機制。

理解


我們這樣理解:
在一定周期內保持不變就是持久化,持久化是針對時間來說的。
資料庫中的數據就是持久化了的數據,只要你不去刪除或修改。
比如在IE瀏覽器中一次Session會話中Session對象變數也是不變的,是Session容器中持久化。
對象持久化的方式有很多種,根據周期不同有,page,Session,Application。
對象序列化機制需要將對象的狀態保存到文件中,而後能夠通過讀入對象狀態來重新構造對象,恢復程序狀態,
對象序列化的過程是對象持久化的方法之一,把對象保存到文件中。

二個層面


簡單的理解持久化可以在二個層面:應用層和系統層、

應用層

如果關閉(shutdown)你的應用然後重新啟動則先前的數據依然存在。

系統層

如果關閉(shutdown)你的系統(電腦)然後重新啟動則先前的數據依然存在。

特點


對象

持久化是一種對象服務,就是把內存中的對象保存到外存中,讓以後能夠取回。需要實現至少3個介面:
void Save(object o) 把一個對象保存到外存中
Object Load(object oid) 通過對象標識從外存中取回對象
boolExists(object oid) 檢查外存中是否存在某個對象
為什麼需要持久化服務呢?那是由於內存本身的缺陷引起的:
內存掉電后數據會丟失,但有一些對象是無論如何都不能丟失的,比如銀行賬號,遺憾的是,人們還無法保證內存永不掉電。
內存過於昂貴,與硬碟、磁帶、光碟等外存相比,內存的價格要高2~3個數量級,而且維持成本也高,至少需要一直供電吧。所以即使對象不需要永久保存,也會因為內存的容量限制不能一直呆在內存中,需要持久化來緩存到外存。

市場

既然持久化服務在看得到的未來還有市場,我們就來看看如何構建一個好的持久化框架,框架是否真的好在於如何在擴展性、縮放性、重用性上取得良好的平衡:
擴展性,如果一個持久性框架不能支持用戶定義的類型,顯然不是一個好的框架。
縮放性,保存和取回對象都需要耗費cpu、帶寬、時間資源,哪一個消耗太多都不能接受。
重用性是我們建立框架的初衷,就是通過框架能夠減少一些編碼和測試的工作量。
這幾個需求往往是互相衝突的,所以關鍵是平衡。

序列化

我們先跳開一下,看看另一個類似的有用概念:序列化也是一種對象服務,就是把內存中的對象序列化成流、或者把流反序列化成對象。需要實現2個介面:
void Serialize(Stream stream,object o) 把對象序列化到流中
object Deserialize(Stream stream) 把流反序列化成對象
序列化和持久化很相似,有些人甚至混為一談,其實還是有區別的,序列化是為了解決對象的傳輸問題,傳輸可以在線程之間、進程之間、內存外存之間、主機之間進行。我之所以在這裡提到序列化,是因為我們可以利用序列化來輔助持久化,可以說凡是可以持久化的對象都可以序列化,因為序列化相對容易一些(也不是很容易),所以主流的軟體基礎設施,比如.net和java,已經把序列化的框架完成了。
持久化方案可以分為關係資料庫方案、文件方案、對象資料庫方案、xml資料庫方案,現今主流的持久化方案是關係資料庫方案,關係資料庫方案不僅解決了併發的問題,更重要的是,關係資料庫還提供了持久化服務之外的價值:統計分析功能。剛才我說到,凡是可以序列化的對象都可以持久化,極端的說,我們可以只建立一個表Object(OID,Bytes),但基本上沒有人這麼做,因為一旦這樣,我們就失去了關係資料庫額外的統計分析功能。
關係資料庫和面向對象之間有一條鴻溝,因為二者模式不匹配,所以就存在一個OR映射問題。

意義


興起原因

當持久化興起的時候,逐漸形成了實體層這個概念了。hibernate,jdo,以及博客園的nbear都可謂是大名鼎鼎!有的公司不使用這種ORM框架,他們使用一些自動生成工具生成實體(例如用Codesmith生成),並生成和該表對應的業務邏輯,於是乎感覺我們的程序好像一下子全都寫好了,下一步就輕鬆了,我們只要擴展業務即可了!莫非這樣真是那麼方便了?在維護上真的是最便捷嗎?其它的持久層解決方案不敢說,但至少我覺得像orm的鼻祖hibernate那種開發機制,在維護還是相當之麻煩呀!一個實體還得對應一個xml文件(雖說這些都可以自動生成),但是你深入項目的時候去想想,我們的業務真能一切都可以定下來嗎?人的思想總是在變的,客戶的需求就更難以琢磨了!哪天我們要給資料庫加個欄位,你想想你必須要走幾步改動?首先我們必須重新生成xml和實體,然後我們必須還得在業務邏輯中增加代碼,還得在視圖層加一個界面(如加一個input輸入框等)!講實話,加一個欄位對這種orm框架的改動還是最少的,哪天假如說我們修改了哪個欄位的名稱、修改了欄位類型,你想想,天吶!很難想像,和這個欄位關聯的程序都得改動!如果名稱改了,ok,你可以全部替換它的原先名稱,改成你新的名稱。那類型改了呢?沒辦法只能手工一個個改掉所有的賦值的類型吧?視圖層、控制層中的驗證(js驗證,業務驗證)、邏輯層、實體層,xml配置等等都必須動。搞啥個hql,這和sql不差不多了嗎(雖然說hql,抽象了資料庫模型)?不過我想沒有程序員不懂sql的吧?況且hql對複雜的語句還是會力不從心的吧!

運用

運用ORM框架勢必會運用大量的反射,代價是犧牲性能。當然現今的各種ORM框架都在嘗試使用各種方法來減輕這塊(LazyLoad,Cache),效果還是很顯著的。可是我們犧牲了這麼大的性能,而且我是覺得在維護上ORM還是最便捷。
真不知道為啥像hibernate這樣的框架還有一個xml配置文件?如果我真ORM的話,我不能把這些數據關係緩存起來,動態取關係不就行了嗎?這樣我不更靈活了嗎?
當然使用ORM也有它的活的活之處,在維護上那種自動生成的方式(petshop模式)比使用ORM框架維護量上更大一些,那種構架如果是每個數據操作對應一個存儲過程的改動會更會讓人暈頭轉向的。其構架大致如以下描述:
主要由BLL,MODEL,DAL三層構架方式實現,BLL存放的是相關業務,MODEL是相關的資料庫表格實體,DAL業務的SQL語句(或存儲過程參數).為了鬆散耦合,在BLL層和DAL層中間加入了工廠層(Factory),其作用是方便DAL層的載體變動(如把Sqlserver改成Mysql),在DAL層有一個setObject資料庫欄位到實體屬性設置,便於資料庫表格映射成實體。
程序編寫的最大問題就是耦合高,怎麼降耦也是開發的一個重中之重。以上述的程序構架來看,如果我改動了資料庫中的其中一個表格的某個欄位,程序改動的至少就有三層。如果再按照自動生成方式那種看,DAL中的update,insert,select, setObject都需要改動,如果存在存儲過程的話,像get,getAll,update,insert都必須改動,想象一下這裡改動地方有幾處了?而且還需改動Model層,修改量之大可見一斑。當然我們這裡可以用自動生成工具生成並替換,可又有誰知道這裡面的替換工作量多少?
總之,提倡"高內聚,低耦合"是構架永恆的話題,尋找便捷亦是構架的終級目標。

相關實現


Hibernate
hibernate為應用程序提供了高效的O/R關係映射和查詢服務,為面向對象的領域模型到傳統的關係型資料庫的映射,提供了一個使用方便的框架。
JPA
JPA(Java Persistense API)是EJB3.0的一部分,為其提供了一套O/R關係映射的API,但不僅限於EJB中使用,它也可以在web應用或者應用程序客戶端中被使用,甚至在Java桌面程序中被使用。
Mybatis
Mybatis也是一種orm框架。