Java Persistence API (JPA)是存取Java關系數據的企業級標准。JPA為Java對象映射到數據庫圖解提 供支持,包括一個簡單的API設計和查詢語言的表達,查詢語言的表達是為了檢索來自數據庫映射的結果 ,並且因為這個結果改變回執 。JPA通過書寫以及維護他們自己的映射代碼、允許存在單一的API而不管 平台、應用服務器或者提供持久執行為開發者提高生產率。這些高速緩存解決方案允許經常的存取實體到 存儲器,可以減少到數據庫查詢的次數和大量花費在轉換數據庫查詢結果到對象上的處理時間。高速緩存 可以深入的積極的對應用性能產生影響。
JPA和數據網格
數據網格是運行在有代表性的低耗硬件群集上面的軟件,支持數據存貯和處理服務。數據網格產品聚 集了處理能源和存儲群集服務的能力,使得客戶端通過API可以使用它,API是為防護設計的,避免分布式 計算的復雜。數據網格作為可伸縮的分布式存儲被普遍運用;無論如何,分布式數據處理也是常見的特性 。作為存儲器,數據網格提供一種方法來超越單一服務器因為堆棧大小的限制,這個解決辦法就是通過分 布式數據存取所有的集群服務器。
盡管他們在專業技術領域內的應用被限制。但是在當今企業應用中,與數據網格相關的話題仍然層出 不窮。數據網格已經成為一種主流,當開發應用程序的時候,開發者需要考慮網格架構,並且意識到在未 來,網格在應用程序中的應用比例會被提高。
考慮一個銀行系統,通過在寫入數據庫前確認所有項目來處理存款和撤銷請求。確認的內容也許包括 帳目是否有效、提出請求的是否是戶主、賬戶上是否有戶主要求提取的存款數額等等。你可以想象,在這 樣一個系統中還有很多需要確認的地方。你需要從數據庫中讀取數據總和,數據總和執行一個確認的單一 請求是有重要意義的,並且會引起很多查詢。幸運的是,在JPA中創建這樣一個以數據庫為中心的應用程 序是非常簡單的。繪制領域內的每一個classe到數據庫,並且書寫必要的JP QL查詢來檢索確認的對象。 系統也許不得不從數據庫讀取大量的數據來處理每一個請求,但是它運作的很好。
現在,如果我們需要顯著的提高這個系統的生產力,我們不得不解決它唯一但是最大的瓶頸:通過查 詢數據庫得出確認數據。大多數JPA執行不是提供一個L2存儲功能,就是支持第三方L2存儲功能的整合。 但是,如果我們不得不處理大量隨機到達的請求,在存儲器中擁有必須的參考數據是不太可能的事情。存 儲器在你重復的存取一些數據是非常的有效。如果你存取的是隨機數據,存儲器不太可能儲存你當即所需 要的數據。當然,你可以不停的增加存儲器的容量來滿足你的需求,但是每一個服務器只能擁有這麼多的 堆棧。
數據網格提供一種方法來超越單一服務器因為堆棧大小而產生的限制以及在集群服務器上分布存儲對 象。現在要面臨的挑戰是將數據網格技術與JPA融合,從而能夠提高生產力,而不需要完全改寫應用程序 。當然,作為軟件系統的代表性案例,有很多案例是接近一體化的,每一個都伴有各自的優勢劣勢。讓我 們來看看整合的體系架構以及我們應該如何使用。
數據網格作為中間級別的對象存儲
像我們前面所提到的,數據網格產品可以擴展存儲,存取一個集群,並且可以作為一個共享的中間存 儲使用。他們提供一個單一的邏輯堆棧,可以從物理層面進行擴展,這種擴展是伴隨著全部的存儲容量在 多重服務器上實現的,全部的存儲容量是包括所有的群集服務器的堆棧。在例子當中,這意味著通過增加 更多的服務器到網格,它的存儲容量可以增加,要點是所有的確認數據必須預先加載(通常是“加熱”存 儲器)。自從確認數據的存取成為我們的瓶頸,存取所有的必須數據在實際上消除了這個問題。
舉例來說,在我們的銀行系統中,考慮一個簡單的可以確定的方法:
public boolean isValidAccount(Request request) {
Account account = entityManager.find(
Account.class, request.getAccountId());
if (account == null) {
return false;
} else {
return account.isValid();
}
}
伴隨著數據網格整合成為L2存儲器,查詢功能將會檢查網格所需要的賬戶。如果不查詢,它可以轉而 查詢基礎數據庫。無論如何,如果網格中包含了所有的帳號信息,這就沒必要查詢數據庫,預熱應用存儲 器可以從確認隊列中完整的清除數據庫存取過程。
主鍵查詢可以很容易的運用到數據網格中,但是JP QL查詢如何那?考慮這種方法,使用非主鍵查詢的 請求:
public Customer getTxCustomer(Request request)
throws NoResultException {
Customer customer = entityManager
.createQuery("select c from Customer c
where c.masterAccountId = :id")
.setParameter("id", request.getMasterAccountId())
.getSingleResult();
return customer;
}
查詢數據網格,得出一個匹配隨意准則的對象仍然是一件困難的事情。首先,它依賴於數據網格是否 提供某種查詢框架,第二,JPA/data網格一體化可以將JP QL轉化為此框架。如果滿足這兩個必要條件, 我們例子中的查詢就可以被應用在網格中,而不是數據庫中。
這種方式的另一個很有價值的特性是執行並行查詢的可能性。顯而易見的是我們例子中的查詢可以在 網格中所有的服務器上並行執行,查找需要的對象。無論如何,一個查詢執行後返回很多的對象是件有趣 的事情。每一個網格服務器都可以執行並行查詢來識別這些對象,使其與被給予的標准相匹配。在10000 個對象上並行執行這種查詢十次比在100,000個對象上查詢一次的速度快得多。服務器越多,每個服務器 上分配的對象數量就越少,查詢速度也就越快!
遺憾的是關於查詢問題還是有一個麻煩,就是返回多重結果。與主鍵查詢不同,主鍵查詢中如果存儲 器失誤會自動的引起數據庫查詢,而現在,是否從網格中得到足夠的結果是不明確的。也許你只能查詢網 格中的一部分對象,所以一個網格查詢是無法返回數據庫中其他部分的查詢結果。通過確保所有的對象都 在網格中,預熱存儲器解決了這個問題, 但這並不總是可行。無論如何,對於一個特定的使用案例,也 許你知道一個特有的查詢是否需要網格或者數據庫。再JPA中通過查詢節點實現查詢功能的。也許就像下 面的演示:
Customer customer = entityManager
.createQuery("select c from Customer c
where c.masterAccountId = :id")
.setParameter("id", request.getMasterAccountId())
.setHint("my-jpa-implementation.dont-query-grid", true)
.getSingleResult();
當然,現在沒有JPA標准來說明是否把查詢用於數據網格。這意味著你不得不在你編譯的代碼中采用特 殊執行的節點。幸運的是,JPA規范依賴於執行,忽略那些不明白的的節點,所以你編譯的代碼並沒有因 為節點而與任何一個特定對象結合。
更新對象
當你看到網格上面的JPA,很自然的你會首先想到查詢,但是我們也不得不考慮更新:輸入新對象,修 改現有對象,以及刪除對象。當網格在L2存儲器中時,確定網格的更新僅僅在數據庫執行過程成功交付之 後產生是非常重要的。輸入新對象會引起數據庫INSERT並且新對象會被放置到網格中。修改對象會引起數 據庫UPDATE,並且被更新的對象會被放置到網格中。最後,刪除一個對象會引起數據庫DELETE,並且這個 對象會從網格中被移除。關鍵點是更新數據網格一次,數據庫執行過程可以成功交付。
數據網格作為系統備份
當JPA使用數據網格作為一個分布式存儲器,數據庫就成為了“系統備份”。這是系統本來面目的最終 來源,並且保持實時更新。但是數據網格實現備份的意義是什麼?這個案例經常使用在金融應用軟件上, 用以處理快速的變化以及過度過程數據。如果沒有數據庫,或者數據庫僅僅被用來存放數據,或者是只是 一個貨艙而不是聯機系統,網格上面的JPA看起來會怎麼樣?