6

Tôi có một ứng dụng được triển khai trong công cụ ứng dụng của Google. Tôi nhận được dữ liệu không phù hợp khi tôi tìm nạp một thực thể theo id ngay sau khi cập nhật thực thể đó. Tôi đang sử dụng JDO 3.0 để truy cập kho dữ liệu của công cụ ứng dụng.Tìm nạp không phù hợp từ kho dữ liệu của Máy ứng dụng của Google

Tôi có một nhân viên tổ chức

@PersistenceCapable(detachable = "true") 
public class Employee implements Serializable { 

    /** 
    * 
    */ 
    private static final long serialVersionUID = -8319851654750418424L; 
    @PrimaryKey 
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY, defaultFetchGroup = "true") 
    @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true") 
    private String id; 
    @Persistent(defaultFetchGroup = "true") 
    private String name; 
    @Persistent(defaultFetchGroup = "true") 
    private String designation;  
    @Persistent(defaultFetchGroup = "true") 
    private Date dateOfJoin;  
    @Persistent(defaultFetchGroup = "true") 
    private String email; 
    @Persistent(defaultFetchGroup = "true") 
    private Integer age; 
    @Persistent(defaultFetchGroup = "true") 
    private Double salary; 
    @Persistent(defaultFetchGroup = "true") 
    private HashMap<String, String> experience; 
    @Persistent(defaultFetchGroup = "true") 
    private List<Address> address; 


    /** 
     * Setters and getters, toString() * */ 

} 

Ban đầu, khi tôi tạo một nhân viên tôi không đặt mức lương lĩnh vực và email.

Tôi cập nhật thực thể Nhân viên để thêm tiền lương và email sau. Bản cập nhật hoạt động tốt và dữ liệu được tiếp tục lưu vào kho dữ liệu appengine. Tuy nhiên, khi tôi ngay lập tức cố gắng lấy cùng một thực thể nhân viên bằng id, đôi khi tôi nhận được dữ liệu cũ, trong đó tiền lương và email là vô giá trị. Mã tôi sử dụng để tạo và tìm nạp thực thể nhân viên được đưa ra dưới đây.

public Employee create(Employee object) { 
     Employee persObj = null; 
     PersistenceManager pm = PMF.get().getPersistenceManager(); 
     Transaction tx = null; 
     try { 
      tx = pm.currentTransaction(); 
      tx.begin(); 

      persObj = pm.makePersistent(object); 

      tx.commit(); 
     } finally { 

      if ((tx != null) && tx.isActive()) { 
       tx.rollback(); 
      } 

      pm.close(); 
     } 

     return persObj; 
    } 


    public Employee findById(Serializable id) { 

     PersistenceManager pm = PMF.get().getPersistenceManager(); 

     try { 
      Employee e = pm.getObjectById(Employee.class, id); 

      System.out.println("INSIDE EMPLOYEE DAO : " + e.toString()); 
      return e; 

     } finally { 

      pm.close(); 

     } 
    } 


    public void update(Employee object) { 
     PersistenceManager pm = PMF.get().getPersistenceManager(); 
     Transaction tx = null; 
     try { 
      tx = pm.currentTransaction(); 
      tx.begin(); 
      Employee e = pm.getObjectById(object.getClass(), object.getId()); 
      e.setName(object.getName()); 
      e.setDesignation(object.getDesignation()); 
      e.setDateOfJoin(object.getDateOfJoin()); 
      e.setEmail(object.getEmail()); 
      e.setAge(object.getAge()); 
     e.setSalary(object.getSalary()); 
      tx.commit(); 
     } finally { 
      if (tx != null && tx.isActive()) { 
       tx.rollback(); 
      } 

      pm.close(); 
     } 
    } 

Tôi đã đặt số lượng phiên bản không hoạt động thành 5 và có khoảng 8 trường hợp chạy cùng một lúc. Khi tôi kiểm tra các bản ghi của các trường hợp khác nhau, đây là những gì tôi tìm thấy. enter image description here

Tại sao tôi nhận dữ liệu cũ khi yêu cầu được phân phối bởi một số trường hợp nhất định. Tôi có thể đảm bảo rằng, nếu yêu cầu tìm nạp được xử lý bởi cá thể ban đầu xử lý yêu cầu cập nhật, tôi luôn nhận được dữ liệu cập nhật. Nhưng khi các trường hợp khác xử lý dữ liệu cũ, yêu cầu tìm nạp có thể được trả lại. Tôi đã đặt rõ ràng kho dữ liệu đọc tính thống nhất để mạnh mẽ trong tệp jdoconfig.xml của tôi.

<?xml version="1.0" encoding="utf-8"?> 
<jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig_3_0.xsd" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig http://java.sun.com/xml/ns/jdo/jdoconfig_3_0.xsd"> 

    <persistence-manager-factory name="transactions-optional"> 
     <property name="javax.jdo.PersistenceManagerFactoryClass" 
      value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/> 
     <property name="javax.jdo.option.ConnectionURL" value="appengine"/> 
     <property name="javax.jdo.option.NontransactionalRead" value="true"/> 
     <property name="javax.jdo.option.NontransactionalWrite" value="true"/> 
     <property name="javax.jdo.option.RetainValues" value="true"/> 
     <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/> 
     <property name="datanucleus.appengine.singletonPMFForName" value="true"/> 
     <property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true"/> 
     <property name="datanucleus.query.jdoql.allowAll" value="true"/>  
     <property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" /> 

    </persistence-manager-factory> 
</jdoconfig> 
+1

http://stackoverflow.com/search?q=%5Bgae%5D+eventual+consistency nhìn vào "nhất cuối cùng" vì điều này nghe có vẻ như thế. –

+0

@PaulCollingwood Tôi đã đặt kho dữ liệu đọc tính thống nhất cho STRONG. HariShankar

+0

http://stackoverflow.com/questions/8112331/google-app-engine-jdo-makepersistent-latency – arundevma

Trả lời

2

Tôi có một gợi ý, tuy nhiên bạn sẽ không thích điều đó: chỉ sử dụng API cấp thấp và quên JDO/JPA khi sử dụng GAE.

Cũng giống như @asp cho biết, nhận được bằng ID được cho là phù hợp mạnh mẽ, tuy nhiên plugin GAE JDO dường như bị lỗi với tôi. Thật không may, việc di chuyển sang JPA cũng không giúp ích gì cho trường hợp của tôi (thêm tại đây: JDO transactions + many GAE instances = overriding data). Ngoài ra, nếu tôi chú thích bất kỳ lớp nào là @PersistenceAware, Eclipse sẽ phát điên và tăng cường các lớp trong vòng lặp vô hạn. Ngoài ra, tôi đã có rất nhiều vấn đề khi sử dụng lớp @PersistenceCapable với lớp nhúng và bộ đệm ẩn (không có bộ nhớ đệm nó hoạt động tốt).

Vâng, vấn đề là, tôi nghĩ rằng nó sẽ nhanh hơn với API cấp thấp - bạn biết chính xác điều gì đang xảy ra và dường như nó hoạt động như dự định. Bạn có thể đối xử với thực thể như một bản đồ, với một chút mã gói tự viết nó có vẻ giống như một thay thế khá thú vị. Tôi chạy một số thử nghiệm và với API cấp thấp tôi đã vượt qua chúng không có vấn đề, trong khi vượt qua nó với JDO/JPA là không thể. Tôi đang di chuyển toàn bộ ứng dụng từ JDO sang API cấp thấp. Đó là thời gian, nhưng ít hơn chờ đợi vô thời hạn cho một số giải pháp kỳ diệu hoặc bugfix từ nhóm GAE.

Ngoài ra, trong khi viết GAE JDO tôi cảm thấy ... một mình. Nếu bạn gặp vấn đề với java, hoặc thậm chí là android, hàng nghìn người khác đã gặp vấn đề này, hãy hỏi về nó trên stackoverflow và nhận được rất nhiều giải pháp hợp lệ. Ở đây bạn là tất cả một mình, do đó, sử dụng như API cấp thấp nhất có thể và bạn sẽ chắc chắn những gì đang xảy ra. Mặc dù di chuyển dường như đáng sợ như địa ngục và tốn thời gian, tôi nghĩ bạn sẽ lãng phí ít thời gian di chuyển sang API cấp thấp hơn so với giao dịch với GAE JDO/JPA. Tôi không viết nó để nhéo nhóm phát triển GAE JDO/JPA hoặc xúc phạm họ, tôi chắc chắn họ làm hết sức mình. Nhưng:

  1. Có không phải là quá nhiều người sử dụng GAE so với, cho phép nói, Android hoặc Java nói chung

  2. Sử dụng GAE JDO/JPA với nhiều trường hợp máy chủ mà không phải là đơn giản và dễ hiểu như bạn sẽ nghĩ. Các nhà phát triển như tôi muốn có công việc của mình được thực hiện càng sớm càng tốt, xem một số ví dụ, đọc một chút tài liệu - không nghiên cứu chi tiết, đọc một hướng dẫn ngắn và nhà phát triển có vấn đề, anh ấy muốn chia sẻ nó trên stackoverflow và nhận trợ giúp nhanh chóng. Thật dễ dàng để nhận trợ giúp nếu bạn làm điều gì đó sai trên Android, cho dù nó có phức tạp hay sai lầm dễ dàng. Nó không dễ dàng với GAE JDO/JPA. Tôi đã dành nhiều thời gian hơn cho các bài viết, hướng dẫn và tài liệu GAE JDO hơn là tôi muốn, và tôi đã thất bại trong việc làm những gì tôi muốn mặc dù nó có vẻ khá cơ bản. Nếu tôi chỉ sử dụng API mức thấp và không cố gắng để có một phím tắt với JDO (yeah, tôi nghĩ rằng JDO sẽ tiết kiệm thời gian của tôi), nó sẽ được nhiều, nhanh hơn nhiều.

  3. Google đang tập trung vào Python GAE nhiều hơn Java. Trong nhiều bài viết được nhắm mục tiêu cho tất cả các đối tượng, có mã Python và gợi ý riêng, ví dụ nhanh ở đây: http://googlecloudplatform.blogspot.com/2013/12/best-practices-for-app-engine-memcache.html hoặc tại đây: https://cloud.google.com/developers/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/. Tôi đã nhận thấy rằng ngay cả trước khi bắt đầu phát triển, nhưng tôi muốn chia sẻ một số mã với khách hàng Android của tôi, vì vậy tôi đã chọn Java. Mặc dù tôi có nền Java vững chắc và ngay cả khi tôi chia sẻ một số mã ngay bây giờ, nếu tôi có thể quay ngược thời gian và chọn lại, tôi sẽ chọn Python ngay bây giờ.

Đó là lý do tại sao tôi nghĩ tốt nhất nên chỉ sử dụng các phương pháp cơ bản nhất để truy cập và thao tác dữ liệu.

Chúc may mắn, tôi chúc bạn mọi điều tốt đẹp nhất.

+0

Tôi đã thử tìm nạp hoạt động bằng API cấp thấp. Nó hoạt động tốt. Phần còn lại của các hoạt động vẫn sử dụng JDO. Không chắc chắn nếu điều đó sẽ gây ra vấn đề hơn nữa. – HariShankar

4

Nếu bạn đang sử dụng kho dữ liệu bản sao cao, hãy đặt chính sách đọc không đảm bảo rằng tất cả các lần đọc đều nhất quán, những chỉ hoạt động cho truy vấn tổ tiên. Từ tài liệu;

API cũng cho phép bạn thiết lập một cách rõ ràng một chính sách nhất quán mạnh mẽ, nhưng thiết lập này sẽ không có hiệu lực thực tế, kể từ khi truy vấn không tổ tiên luôn cuối cùng phù hợp bất kể chính sách.

https://cloud.google.com/appengine/docs/java/datastore/queries#Java_Data_consistency https://cloud.google.com/appengine/docs/java/datastore/jdo/overview-dn2#Setting_the_Datastore_Read_Policy_and_Call_Deadline

hãy có một cái nhìn tại các tài liệu về Structuring Data for Strong Consistency, cách tiếp cận thích hợp nhất là đến lớp bộ nhớ đệm để phục vụ dữ liệu.

Tôi nhận thấy rằng bạn đang sử dụng ID, không chắc chắn, nhưng "nhận được bằng khóa" được cho là nhất quán ngay cả đối với kho dữ liệu HR (reference), bạn có thể thử thay đổi điều này thành truy vấn dựa trên khóa không? Khóa được tạo bằng cách sử dụng id và loại thực thể và tổ tiên.

Các vấn đề liên quan