Xem mẫu

  1. Máy ứng dụng của Google cho Java: Phần 3: Lưu giữ lâu bền và các mối quan hệ Lưu giữ lâu bền dựa vào Java và kho lưu trữ dữ liệu của Máy ứng dụng của Google Rick Hightower , Giám đốc, eBlox Tóm tắt: Lưu giữ lâu bền dữ liệu là một phần quan trọng của việc phân phối ứng dụng có khả năng mở rộng trong các môi trường doanh nghiệp. Trong bài viết cuối cùng của loạt bài giới thiệu của mình về Máy ứng dụng của Google (Google App Engine) cho Java™, Rick Hightower chấp nhận các thách thức của các khung công tác lưu giữ lâu bền dựa trên Java hiện có của Máy ứng dụn g (App Engine). Tìm hiểu các chi tiết về tại sao việc lưu giữ lâu bền bằng Java trong bản các phát hành trước đây chưa phải là hoàn toàn sẵn sàng cho thời kỳ cao điểm, đồng thời cũng nhận được một trình diễn làm việc thực sự về những gì mà bạn có thể làm để lưu giữ lâu bền dữ liệu trong các ứng dụng của Máy ứng dụng cho Java. Chú ý rằng bạ Máy ứng dụng cho Java cố gắng loại bỏ mối lo phải viết một tầng lưu giữ lâu bền cho các ứng dụng Web mở rộng được, nhưng nó thực hiện mục đích đó đến mức nào? Trong bài viết này, tôi kết thúc bài giới thiệu của mình về Máy ứng dụng cho Java với một tổng quan về khung công tác lưu giữ lâu bền của nó, dựa trên các đối tượng dữ liệu Java (Java Data Objects-JDO) và API lưu giữ lâu bền của Java (Java Persistence API-JPA). Mặc dù ban đầu tỏ ra nhiều hứa hẹn, việc lưu giữ lâu bền dựa trên Java của Máy ứng dụng hiện tại có một số nhược điểm nghiêm trọng mà tôi sẽ giải thích và chứng tỏ các nhược điểm đó. Bạn sẽ tìm hiểu xem việc lưu giữ lâu bền của Máy ứng dụng cho Java hoạt động như thế nào, những thách thức là gì và bạn có những tùy chọn lưu giữ lâu bền nào khi làm việc với nền tảng đám mây của Google dành cho các nhà phát triển Java. Khi bạn đọc bài viết này và làm việc qua các ví dụ, bạn sẽ muốn ghi nhớ một thực tế là Máy ứng dụng cho Java hiện nay là một bản phát hành xem trước. Khi mà việc lưu giữ lâu bền dựa trên Java có thể không phải là tất cả những gì mà bạn có thể hy vọng, hoặc cần có, vào lúc này, điều này là có thể và cần thay đổi trong tương lai. Những gì mà tôi học được trong khi viết bài hướng dẫn này là việc sử dụng Máy ứng dụng cho Java để phát triển ứng dụng Java tập trung vào dữ liệu, có khả năng mở rộng, hiện nay, không phải dành cho những người nhút nhát hay bảo thủ. Nó giống như lặn xuống đáy bể bơi: Không còn ở trong tầm mắt của người cứu hộ nữa và dự án của bạn chìm xuồng hoặc bơi được là tùy thuộc nơi bạn.
  2. Chú ý rằng ứng dụng ví dụ trong bài viết này được dựa trên ứng dụng quản lý liên hệ đã phát triển trong Phần 2 của bài viết này. Bạn sẽ cần phải có ứng dụng đó đã xây dựng và chạy được để tiếp tục các ví dụ ở đây. Thành phần cơ bản và các sự trừu tượng hóa có lỗ rò Cũng giống như Máy ứng dụng của Google nguyên thủy, Máy ứng dụng cho Java dựa vào cơ sở hạ tầng nội bộ của Google với Ba Trụ Lớn (Big Three) để phát triển ứng dụng có khả năng mở rộng: phân tán, tạo bản sao và cân bằng tải. Vì bạn đang làm việc với cơ sở hạ tầng của Google, nên hầu hết các phép thuật này xảy ra ở hậu trường và bạn có thể truy cập qua các API tiêu chuẩn của Máy ứng dụng cho Java. Giao diện kho lưu trữ dữ liệu (datastore) được dựa trên JDO và JPA, mà chính chúng lại dựa trên dự án nguồn mở DataNucleus. Máy ứng dụng cho Java cũng cung cấp một API tiếp hợp (adapter) mức thấp để làm việc trực tiếp với kho lưu trữ dữ liệu của Máy ứng dụng cho Java, kho lưu trữ dữ liệu này dựa trên việc thực hiện BigTable của Google (xem Phần 1 để biết thêm về BigTable). Tuy nhiên, việc lưu giữ lâu bền dữ liệu của Máy ứng dụng cho Java là không hoàn toàn đơn giản như việc lưu giữ lâu bền trong Máy ứng dụng của Google thuần. Các giao diện JDO và JPA lộ ra một số sự trừu tượng hóa có lỗ rò do thực tế là BigTable không phải là một cơ sở dữ liệu quan hệ. Ví dụ, trong Máy ứng dụng cho Java, bạn không thể thực hiện các truy vấn mà chúng thực hiện các phép nối (join). Bạn có thể thiết lập các quan hệ trong JPA và JDO, nhưng chúng chỉ có thể được sử dụng để lưu giữ lâu bền các quan hệ. Và khi bạn lưu giữ lâu bền các đối tượng, chúng chỉ có thể được duy trì trong cùng một giao dịch nguyên tử nếu chúng ở trong cùng một nhóm thực thể. Theo quy ước, các quan hệ là quan hệ sở hữu nằm trong cùng nhóm thực thể với thực thể cha mẹ. Ngược lại, các mối quan hệ không sở hữu nằm trong các nhóm thực thể tách biệt. Nghĩ lại về chuẩn hóa dữ liệu Làm việc với kho lưu trữ dữ liệu có khả năng mở rộng của Máy ứng dụng đòi hỏi bạn phải suy nghĩ lại luận thuyết của mình về các lợi ích của dữ liệu được chuẩn hóa. Tất nhiên, nếu bạn đã làm việc đủ lâu trong thế giới thực, có thể bạn đã phải một hai lần hy sinh sự chuẩn hóa để đổi lấy hiệu năng. Sự khác biệt là, khi làm việc với kho lưu trữ dữ liệu của Máy ứng dụng, bạn phải không chuẩn hóa sớm hơn và thường xuyên. Chưa chuẩn hóa không còn là một từ xấu nữa; thay vào đó, nó là một công cụ thiết kế mà bạn sẽ áp dụng trong nhiều khía cạnh của các ứng dụng của Máy ứng dụng cho Java của bạn. Nhược điểm chính với Máy ứng dụng cho sự lưu giữ lâu bền có lỗ rò của Java sẽ xuất hiện khi bạn cố gắng chuyển một ứng dụng được viết cho một RDBMS tới Máy ứng dụng cho Java. Kho lưu trữ dữ liệu của Máy ứng dụng cho Java không
  3. phải là một sự thay thế ngay lập tức cho một c ơ sở dữ liệu quan hệ, do đó, những gì mà bạn làm với Máy ứng dụng cho Java có thể không dễ dàng diễn dịch để chuyển sang cho RDBMS. Lấy một lược đồ hiện có và mang nó sang kho lưu trữ dữ liệu là một kịch bản thậm chí ít khả năng hơn. Nếu bạn quyết định chuyển một ứng dụng doanh nghiệp Java kế thừa tới Máy ứng dụng, hãy nên tiến hành thận trọng và sao lưu nó với bản phân tích. Máy ứng dụng của Google là một nền tảng dành cho các ứng dụng được thiết kế riêng biệt cho nó. Sự hỗ trợ của Máy ứng dụng của Google cho Java cho JDO và JPA cho phép các ứng dụng này được chuyển ngược trở lại thành các ứng dụng doanh nghiệp truyền thống hơn, dù là chưa chuẩn hóa. Những rắc rối với các mối quan hệ Một nhược điểm khác của Máy ứng dụng cho Java trong bản phát hành xem trước hiện nay là việc xử lý các quan hệ của nó. Để tạo các quan hệ, hiện tại bạn phải sử dụng các phần mở rộng cho JDO đặc thù riêng cho Máy ứng dụng cho Java. Biết rằng các khóa được tạo ra dựa trên các tạo phẩm của BigTable — đó là, "khóa chính " có khóa đối tượng-cha mẹ được mã hóa vào tất cả các khóa của con của nó — bạn sẽ phải quản lý dữ liệu của mình trong một cơ sở dữ liệu không quan hệ. Một hạn chế khác là việc lưu giữ lâu bền dữ liệu. Các sự phức tạp nảy sinh nếu bạn sử dụng lớp Key (Khóa) không tiêu chuẩn của Máy ứng dụng cho Java. Trước hết, bạn sử dụng Key không tiêu chuẩn như thế nào khi chuyển mô hình của bạn sang một RDBMS? Thứ hai, máy GWT không thể dịch lớp Key, vì thế bất kỳ đối tượng mô hình nào sử dụng lớp này không thể được sử dụng như một phần của ứng dụng GWT của bạn. Tất nhiên, tại thời điểm viết bài này, Máy ứng dụng của Google cho Java mới chỉ là ở chế độ xem trước. Nó không được xem là đã sẵn sàng cho thời kỳ cao điểm. Điều này trở nên càng rõ ràng hơn khi nghiên cứu tài liệu hướng dẫn về các quan hệ trong JDO, rất thưa thớt và chứa các ví dụ chưa hoàn chỉnh. Bộ công cụ phát triển của Máy ứng dụng cho Java được gửi kèm một loạt các chương trình ví dụ. Nhiều ví dụ trong đó sử dụng JDO, mà không sử dụng JPA. Không có một ví dụ nào (kể cả ví dụ có tên là jdoexamples) nêu thí dụ về một quan hệ dù là đơn giản. Thay vào đó, tất cả các ví dụ chỉ sử dụng một đối tượng để lưu trữ dữ liệu trong kho lưu trữ dữ liệu. Nhóm thảo luận về Máy ứng dụng của Google cho Java bị tràn ngập những câu hỏi về cách làm thế nào để một quan hệ đơn giản hoạt động được, với vài câu trả lời. Một số nhà phát triển hình như đã có khả năng làm cho nó hoạt động, nhưng rất vất vả và gặp một số khó khăn. Điểm mấu chốt về các quan hệ trong Máy ứng dụng cho Java là bạn cần phải quản lý chúng mà không được hỗ trợ nhiều từ JDO hay JPA. Tuy nhiên, BigTable của Google là một công nghệ đã được thử thách để sản xuất các ứng dụng có khả năng
  4. mở rộng và bạn có thể xây dựng bên trên nó. Việc xây dựng bên trên BigTable giải phóng bạn, không cần phải làm việc với mặt ngoài API, còn chưa được hậu thuẫn đầy đủ. Mặt khác, bạn sẽ phải làm việc với một API mức thấp hơn. JDO trong Máy ứng dụng cho Java Khi mà việc chuyển một ứng dụng Java truyền thống sang Máy ứng dụng cho Java có thể không có ý nghĩa và thậm chí đã biết rằng có những thách thức về các quan hệ, vẫn có các kịch bản lưu giữ lâu bền mà ở đây việc sử dụng nền tảng này là có ý. Tôi sẽ kết thúc bài này bằng một ví dụ làm việc được, mang lại cho bạn một hương vị về việc Máy ứng dụng cho Java thực hiện lưu giữ lâu bền như thế nào. Chúng ta sẽ bắt đầu với ứng dụng quản lý-liên hệ được xây dựng trong Phần 2, lần này đi qua các thủ tục để thêm hỗ trợ cho việc lưu giữ lâu bền các đối tượng Contact bằng các phương tiện của kho lưu trữ dữ liệu của Máy ứng dụng cho Java. Trong bài trước, bạn đã tạo một GWT GUI đơn giản thực hiện các hoạt động CRUD trên các đối tượng Contact. Bạn đã định nghĩa giao diện đơn giản như thấy trong Liệt kê 1: Liệt kê 1. Giao diện ContactDAO đơn giản 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);
  5. void updateContact(Contact contact); List listContacts(); } Tiếp theo, bạn đã tạo ra một phiên bản giả, làm việc với dữ liệu trong một bộ sưu tập nằm ở bộ nhớ, như thấy trong Liệt kê 2: Liệt kê 2. ContactDAOMock làm giả DAO 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 {
  6. Map map = new LinkedHashMap(); { map.put("rhightower@mammatus.com", new Contact("Rick Hightower", "rhightower@mammatus.com", "520-555-1212")); map.put("scott@mammatus.com", new Contact("Scott Fauerbach", "scott@mammatus.com", "520-555-1213")); map.put("bob@mammatus.com", new Contact("Bob Dean", "bob@mammatus.com", "520-555-1214")); } public void addContact(Contact contact) { String email = contact.getEmail(); map.put(email, contact); } public List listContacts() { return Collections.unmodifiableList(new ArrayList(map.values())); }
  7. public void removeContact(Contact contact) { map.remove(contact.getEmail()); } public void updateContact(Contact contact) { map.put(contact.getEmail(), contact); } } Bây giờ hãy xem điều gì sẽ xảy ra khi bạn thay thế việc thực hiện mô hình giả bằng một phiên bản của ứng dụng tương tác với kho lưu trữ dữ liệu của Máy ứng dụng của Google. Với ví dụ này, bạn sẽ sử dụng JDO để lưu giữ lâu bền lớp Contact. Một ứng dụng được viết bằng cách sử dụng các trình cắm thêm Eclipse của Google (Google Eclipse Plugin) đã có tất cả các thư viện mà nó cần để sử dụng JDO. Nó cũng bao gồm một tệp jdoconfig.xml, do đó một khi bạn chú giải lớp Contact, bạn sẽ sẵn sàng để bắt đầu sử dụng JDO. Liệt kê 3 cho thấy giao diện ContactDAO được mở rộng để sử dụng API JDO để lưu giữ lâu bền, truy vấn, cập nhật và xóa các đối tượng: Liệt kê 3. ContactDAO với JDO package gaej.example.contact.server;
  8. 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 {
  9. pm.makePersistent(contact); } finally { pm.close(); } } @SuppressWarnings("unchecked") public List listContacts() { PersistenceManager pm = getPersistenceManagerFactory() .getPersistenceManager(); String query = "select from " + Contact.class.getName(); return (List) 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,
  10. 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();
  11. // 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(); } } } Theo từng phương thức Bây giờ chúng ta hãy xem xét những gì đang xảy ra với mỗi một trong các phương thức trong Liệt kê 3. Bạn sẽ thấy rằng trong khi các tên phương thức có thể là mới, hành động của chúng phần nhiều là đã quen thuộc.
  12. Trước tiên, để truy cập vào PersistenceManager, bạn đã tạo ra một PersistenceManagerFactory tĩnh. Nếu bạn đã làm việc với JPA từ trước, PersistenceManager tương tự với một EntityManager trong JPA. Nếu bạn đã làm việc với Hibernate, PersistenceManager tương tự như một phiên Hibernate. Về bản chất, PersistenceManager là giao diện chính cho hệ thống lưu giữ lâu bền JDO. Nó đại diện cho một phiên làm việc với cơ sở dữ liệu. Phương thức getPersistenceManagerFactory() trả về PersistenceManagerFactory, được khởi tạo tĩnh, như chỉ ra trong Liệt kê 4: Liệt kê 4. getPersistenceManagerFactory() trả về PersistenceManagerFactory private static final PersistenceManagerFactory pmfInstance = JDOHelper .getPersistenceManagerFactory("transactions-optional"); public static PersistenceManagerFactory getPersistenceManagerFactory() { return pmfInstance; } Phương thức addContact() bổ sung thêm một mối liên hệ mới vào kho lưu trữ dữ liệu này. Để làm điều này, nó cần phải tạo ra một cá thể của PersistenceManager và sau đó gọi phương thức makePersistence() của PersistenceManager này. Phương thức makePersistence() lấy đối tượng Contact tạm thời (mà người dùng sẽ phải điền vào trong GWT GUI) và làm cho nó thành một đối tượng lưu giữ lâu bền. Tất cả những việc này được thể hiện trong Liệt kê 5: Liệt kê 5. addContact()
  13. public void addContact(Contact contact) { PersistenceManager pm = getPersistenceManagerFactory() .getPersistenceManager(); try { pm.makePersistent(contact); } finally { pm.close(); } } Chú ý trong Liệt kê 5 persistenceManager được gói trong một khối finally như thế nào. Điều này đảm bảo nó xóa nguồn tài nguyên kết hợp với persistenceManager. Phương thức listContact(), được hiển thị trong Liệt kê 6, tạo ra một đối tượng truy vấn từ persistenceManager mà nó tìm kiếm. Nó gọi phương thức execute(), trả về danh sách các Contact từ kho lưu trữ dữ liệu. Liệt kê 6. listContact() @SuppressWarnings("unchecked") public List listContacts() { PersistenceManager pm = getPersistenceManagerFactory()
  14. .getPersistenceManager(); String query = "select from " + Contact.class.getName(); return (List) pm.newQuery(query).execute(); } Phương thức removeContact() tìm kiếm mối liên hệ bằng mã nhận dạng (ID) trước khi nó loại bỏ mối liên hệ ấy khỏi kho lưu trữ dữ liệu, như chỉ ra trong Liệt kê 7. Nó phải làm điều này chứ không phải chỉ xóa ngay mối liên hệ vì đối tượng Contact đến từ GWT GUI không biết gì về JDO. Bạn phải lấy ra một Contact được kết hợp với một vùng nhớ nhanh (cache) của PersistenceManager trước khi bạn có thể xóa nó. Liệt kê 7. removeContact() 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());
  15. pm.deletePersistent(contact); pm.currentTransaction().commit(); } catch (Exception ex) { pm.currentTransaction().rollback(); throw new RuntimeException(ex); } finally { pm.close(); } } Phương thức updateContact(), trong Liệt kê 8, tương tự như phương thức removeContact(), ở chỗ là nó cũng tìm kiếm Contact. Phương thức updateContact() sau đó sao chép các thuộc tính từ Contact. Các thuộc tính này được chuyển như một đối số đến Contact, đã được tìm kiếm với trình quản lý lưu giữ lâu bền. PersistenceManager kiểm tra các thay đổi của các đối tượng được tìm kiếm. Nếu một đối tượng đã thay đổi, các thay đổi này được PersistenceManager trút sang cơ sở dữ liệu khi một giao dịch cam kết. Liệt kê 8. updateContact() public void updateContact(Contact contact) { PersistenceManager pm = getPersistenceManagerFactory() .getPersistenceManager();
  16. 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(); } }
  17. Chú giải cho việc lưu giữ lâu bền đối tượng Để một Contact được lưu giữ lâu bền, bạn phải nhận biết nó như là một đối tượng có khả năng - lưu giữ lâu bền với chú giải @PersistenceCapable. Sau đó bạn cần phải chú giải tất cả các trường có khả năng lưu giữ lâu bền của nó, như thể hiện trong Liệt kê 9: Liệt kê 9. Contact có khả năng lưu giữ lâu bền package gaej.example.contact.client; import java.io.Serializable; import javax.jdo.annotations.IdGeneratorStrategy; import javax.jdo.annotations.IdentityType; import javax.jdo.annotations.PersistenceCapable; import javax.jdo.annotations.Persistent; import javax.jdo.annotations.PrimaryKey; @PersistenceCapable(identityType = IdentityType.APPLICATION) public class Contact implements Serializable { private static final long serialVersionUID = 1L; @PrimaryKey
  18. @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id; @Persistent private String name; @Persistent private String email; @Persistent private String phone; public Contact() { } public Contact(String name, String email, String phone) { super(); this.name = name; this.email = email; this.phone = phone; } public Long getId() { return id;
  19. } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; }
  20. public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } } Nhờ sự kỳ diệu của lập trình hướng đối tượng và các nguyên lý thiết kế bằng giao diện, bạn có thể thay thế ContactDAOMock ban đầu của bạn bằng ContactJdoDAO mới. GWT GUI sau đó sẽ làm việc với JDO mà không cần thay đổi. Cuối cùng, cái thực sự thay đổi với sự trao đổi này là cách mà DAO được thuyết minh trong dịch vụ, như thể hiện trong Liệt kê 10: Liệt kê 10. RemoteServiceServlet public class ContactServiceImpl extends RemoteServiceServlet implements ContactService { private static final long serialVersionUID = 1L; //private ContactDAO contactDAO = new ContactDAOMock(); private ContactDAO contactDAO = new ContactJdoDAO();
nguon tai.lieu . vn