歡迎您光臨本站 註冊首頁

基於 Java 的持久性和 Google App Engine 數據存儲

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  
在企業環境中,數據持久性是交付可伸縮應用程序的基礎。Rick Hightower 在他撰寫的有關 Google App Engine for Java™ 的系列文章的最後一篇中,介紹了 App Engine 當前基於 Java 的持久性框架。讓我們學習一些基礎知識,了解為什麼當前預覽版中的 Java 持久性還未到發布的最佳時間,同時獲得一個良好的演示,看看您如何在 App Engine for Java 應用程序中保存數據。注意,您將需要啟動並運行來自 第 2 部分 的聯繫人管理應用程序,在此過程中學習如何使用 JDO API 保存、查詢、更新和刪除 Contact 對象。

App Engine for Java 力求為可伸縮的 Web 應用程序成功地編寫一個持久層,可這個目標的達成情況又如何呢?在本文中,我將概述 App Engine for Java 的持久性框架,從而結束本系列文章。該框架以 Java Data Objects(JDO)和 Java Persistence API(JPA)為基礎。儘管在剛剛出現時前景良好,但是 App Engine 的基於 Java 的持久性目前存在一些嚴重的缺陷,我將對此進行解釋和演示。您將學習 App Engine for Java 持久性是如何運作以及有著哪些挑戰,還將學習在使用面向 Java 開發人員的 Google 雲平台時,您具有哪些持久性選擇。

雲計算空間

您是否希望隨時獲取最新的雲計算消息?是否想得到雲計算相關的技術知識?developerWorks 雲計算空間就是這樣一個雲計算信息資源的門戶,在這裡您可以了解來自 IBM 和業界其他媒體的最新信息,並且得到如何在雲環境中使用 IBM 軟體的入門知識。

IBM 在 Amazon EC2 雲計算環境中提供了 DB2、Informix、Lotus、WebSphere 等方面的 AMI 鏡像資源。您只需按使用量支付少量費用,就可以使用到雲上的數據、門戶、Web 內容管理、情景應用等服務。歡迎您隨時訪問 雲計算空間,獲取更多信息。

在閱讀本文並遍覽這些示例時,您要牢記這樣的事實:現在的 App Engine for Java 是一個預覽 版。基於 Java 的持久性目前也許並不是您所希望或者需要的全部,可能並且應該會在未來發生變化。現如今,使用 App Engine for Java 進行可伸縮的、數據密集型的 Java 應用程序開發不合適膽小者或者保守派,這就是我在撰寫本文時所學到的。這更像跳入了游泳池的最深處:看不到任何救生員,項目要沉下去還是往前游,取決於您自己。

注意,本文中的示例應用程序以 第 2 部分 中開發的聯繫人管理應用程序為基礎。您需要構建該應用程序,確保它是可運行的,這樣才能繼續學習本文的示例。

基礎知識和抽象泄漏(leaky abstraction)

與原始的 Google App Engine 一樣,App Engine for Java 依靠 Google 的內部基礎設施,實現可伸縮的應用程序開發的 Big Three:分佈、複製和負載均衡。由於使用的是 Google 基礎設施,因此所有神奇的地方大都發生在後台,可以通過 App Engine for Java 的基於標準的 API 獲得。數據存儲介面是以 JDO 和 JPA 為基礎的,而它們自身又是以開源的 DataNucleus 項目為基礎。AppEngine for Java 還提供了一個低級別的適配器 API,用來直接處理基於 Google 的 BigTable 實現的 App Engine for Java 數據存儲(要了解更多有關 BigTable 的信息,請參見 第 1 部分)。

然而,App Engine for Java 數據持久性並不像純 Google App Engine 中的持久性那樣簡單。由於 BigTable 不是一個關係資料庫,JDO 和 JPA 的介面出現了一些抽象泄漏。例如,在 App Engine for Java 中,您無法進行那些執行連接的查詢。您可以在 JPA 和 JDO 間設置關係,但它們只能用來持久化關係。並且在持久化對象時,如果它們在相同的實體群中,那麼它們只能被持久化到相同的原子事務中。根據慣例,具有所有權的關係位於與父類相同的實體群中。相反,不具有所有權的關係可以在不同的實體群中。

重新考慮數據規範化

要使用 App Engine 的可伸縮的數據存儲,需要重新考慮有關規範化數據的優點的教導。當然,如果您在真實的環境中工作了足夠長的時間,那麼,您可能已經為了追求性能而犧牲過規範化了。區別在於,在處理 App Engine 數據存儲時,您必須儘早且經常進行反規範化。反規範化 不再是一個忌諱的字眼,相反,它是一個設計工具,您可以把它應用在 App Engine for Java 應用程序的許多方面。

當您嘗試把為 RDBMS 編寫的應用程序移植到 App Engine for Java 時,App Engine for Java 的持久性泄漏的主要缺陷就會顯露出來。App Engine for Java 數據存儲並不是關係資料庫的臨時替代物,因此,要把您對 App Engine for Java 所做的工作移植到 RDBMS 埠並不容易。採用現有的模式並把它移植到數據存儲中,這種場景則更為少見。如果您決定把一個遺留的 Java 企業應用程序移植到 App 引擎中,建議您要小心謹慎,並進行備份分析。Google App Engine 是一個針對專門為它設計的應用程序的平台。Google App Engine for Java 支持 JDO 和 JPA,這使得這些應用程序能夠被移植回更傳統的、未進行規範化的企業應用程序。

關係的問題

App Engine for Java 目前的預覽版的另外一個缺點是它對關係的處理。為了創建關係,現在您必須對 JDO 使用 App Engine for Java 特有的擴展。假設鍵是在 BigTable 的工件的基礎上生成 — 也就是說,“主鍵” 將父對象鍵編碼到其所有子鍵中 — 您將不得不在一個非關係資料庫中管理數據。另外一個限制是持久化數據。如果您使用非標準的 AppEngine for Java Key 類,事情將會變得複雜。首先,把模型移植到 RDBMS 時,如何使用非標準 Key? 其次,由於無法使用 GWT 引擎轉換 Key 類,因此,任何使用這個類的模型對象都無法被作為 GWT 應用程序的一部分進行使用。

當然,撰寫這篇文章時,Google App Engine for Java 還是純粹的預覽模式,沒有到發布的最佳時間。學習 JDO 中的關係文檔(很少,而且包含一些不完整的示例)時,這點就變得顯而易見了。

App Engine for Java 開發包提供了一系列的示常式序。許多示例都使用 JDO,沒有一個使用 JPA。這些示例中沒有一個示例(包括一個名為 jdoexamples 的示例)演示了關係,即使是簡單的關係。相反,所有的示例都只使用一個對象把數據保存到數據存儲中。Google App Engine for Java 討論組 充斥著有關如何使簡單關係起作用的問題,但卻鮮有答案。很顯然,有些開發人員有辦法使其起作用,但是實現起來都很困難,而且遇到了一些複雜情況。

App Engine for Java 中的關係的底線是,無需從 JDO 或 JPA 獲得大量支持就能夠管理它們。 Google 的 BigTable 是一種已經經過檢驗的技術,可用來生成可伸縮的應用程序,然而,您還可以在此基礎上進行構建。在 BigTable 上進行構建,您就不必處理還不完善的 API 層面。另一方面,您只要處理一個較低級別的 API。

App Engine for Java 中的 Java Data Objects

把傳統的 Java 應用程序移植到 App Engine for Java 中,甚至是給出關係挑戰,這些可能都沒有什麼意義,然而,持久性場景還是存在的,這時使用這個平台就有意義了。我將使用一個可行的示例來結束本文,您將體驗 App Engine for Java 持久性是如何工作的。我們將以 第 2 部分 中建立的聯繫人管理應用程序為基礎,介紹如何添加支持,以使用 App Engine for Java 數據存儲工具持久化 Contact 對象。

在前面的文章中,您創建了一個簡單的 GWT GUI,對 Contact 對象進行 CRUD 操作。您定義了簡單的介面,如清單 1 所示:


清單 1. 簡單的 ContactDAO 介面
				  package gaej.example.contact.server;    import java.util.List;    import gaej.example.contact.client.Contact;    public interface ContactDAO {  	void addContact(Contact contact);  	void removeContact(Contact contact);  	void updateContact(Contact contact);  	List<Contact> listContacts();  }    

接下來,創建一個模擬版本,與內存集合中的數據進行交互,如清單 2 所示:


清單 2. 模擬 DAO 的 ContactDAOMock
				  package gaej.example.contact.server;    import gaej.example.contact.client.Contact;    import java.util.ArrayList;  import java.util.Collections;  import java.util.LinkedHashMap;  import java.util.List;  import java.util.Map;    public class ContactDAOMock implements ContactDAO {    	Map<String, Contact> map = new LinkedHashMap<String, Contact>();  	  	{  		map.put("[email protected]", new Contact("Rick Hightower",                                    "[email protected]", "520-555-1212"));  		map.put("[email protected]", new Contact("Scott Fauerbach",                                    "[email protected]", "520-555-1213"));  		map.put("[email protected]ammatus.com", new Contact("Bob Dean",                                    "[email protected]", "520-555-1214"));    	}  	  	public void addContact(Contact contact) {  		String email = contact.getEmail();  		map.put(email, contact);  	}    	public List<Contact> listContacts() {  		return Collections.unmodifiableList(new ArrayList<Contact>(map.values()));  	}    	public void removeContact(Contact contact) {  		map.remove(contact.getEmail());  	}    	public void updateContact(Contact contact) {		  		map.put(contact.getEmail(), contact);  	}    }    

現在,使用與 Google App Engine 數據存儲交互的應用程序替換模擬實現,看看會發生什麼。在這個示例中,您將使用 JDO 持久化 Contact 類。使用 Google Eclipse Plugin 編寫的應用程序已經擁有了使用 JDO 所需的所有庫。它還包含了一個 jdoconfig.xml 文件,因此,一旦對 Contact 類進行了註釋,您就已經準備好開始使用 JDO。

清單 3 顯示擴展后的 ContactDAO 介面,可使用 JDO API 進行持久化、查詢、更新和刪除對象:


清單 3. 使用 JDO 的 ContactDAO
				  package gaej.example.contact.server;    import gaej.example.contact.client.Contact;    import java.util.List;    import javax.jdo.JDOHelper;  import javax.jdo.PersistenceManager;  import javax.jdo.PersistenceManagerFactory;    public class ContactJdoDAO implements ContactDAO {  	private static final PersistenceManagerFactory pmfInstance = JDOHelper  			.getPersistenceManagerFactory("transactions-optional");    	public static PersistenceManagerFactory getPersistenceManagerFactory() {  		return pmfInstance;  	}    	public void addContact(Contact contact) {  		PersistenceManager pm = getPersistenceManagerFactory()  				.getPersistenceManager();  		try {  			pm.makePersistent(contact);  		} finally {  			pm.close();  		}  	}    	@SuppressWarnings("unchecked")  	public List<Contact> listContacts() {  		PersistenceManager pm = getPersistenceManagerFactory()  				.getPersistenceManager();  		String query = "select from " + Contact.class.getName();  		return (List<Contact>) pm.newQuery(query).execute();  	}    	public void removeContact(Contact contact) {  		PersistenceManager pm = getPersistenceManagerFactory()  				.getPersistenceManager();  		try {  			pm.currentTransaction().begin();    			// We don't have a reference to the selected Product.  			// So we have to look it up first,  			contact = pm.getObjectById(Contact.class, contact.getId());  			pm.deletePersistent(contact);    			pm.currentTransaction().commit();  		} catch (Exception ex) {  			pm.currentTransaction().rollback();  			throw new RuntimeException(ex);  		} finally {  			pm.close();  		}  	}    	public void updateContact(Contact contact) {  		PersistenceManager pm = getPersistenceManagerFactory()  				.getPersistenceManager();  		String name = contact.getName();  		String phone = contact.getPhone();  		String email = contact.getEmail();    		try {  			pm.currentTransaction().begin();  			// We don't have a reference to the selected Product.  			// So we have to look it up first,  			contact = pm.getObjectById(Contact.class, contact.getId());  			contact.setName(name);  			contact.setPhone(phone);  			contact.setEmail(email);  			pm.makePersistent(contact);  			pm.currentTransaction().commit();  		} catch (Exception ex) {  			pm.currentTransaction().rollback();  			throw new RuntimeException(ex);  		} finally {  			pm.close();  		}  	}    }  


[火星人 ] 基於 Java 的持久性和 Google App Engine 數據存儲已經有545次圍觀

http://coctec.com/docs/linux/show-post-68738.html