6

Ho un'applicazione distribuita nel motore di app di Google. Ricevo dati incoerenti quando richiamo un'entità per ID subito dopo l'aggiornamento di tale entità. Sto usando JDO 3.0 per accedere al datastore del motore dell'app.Fetch incoerente dal datastore del Google App Engine

Ho un dipendente un'entità

@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() * */ 

} 

Inizialmente, quando creo un dipendente non stabilire il salario campi ed e-mail.

Aggiornare l'entità Dipendente per aggiungere salario e e-mail in seguito. L'aggiornamento funziona correttamente e i dati vengono mantenuti nel datastore appengine. Tuttavia, quando provo immediatamente a recuperare la stessa entità dipendente dall'ID, a volte ottengo i dati non aggiornati, dove lo stipendio e l'email sono nulli. Di seguito viene fornito il codice che uso per creare e recuperare l'entità dipendente.

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(); 
     } 
    } 

Ho impostato il numero di istanze inattive su 5 e ci sono circa 8 istanze in esecuzione alla volta. Quando ho controllato i registri di varie istanze questo è quello che ho trovato. enter image description here

Perché ottengo dati obsoleti quando la richiesta viene servita da determinate istanze. Posso assicurare che, se la richiesta di recupero viene gestita dall'istanza che inizialmente gestiva la richiesta di aggiornamento, ottengo sempre i dati aggiornati. Ma quando altre istanze gestiscono la richiesta di recupero, i dati non aggiornati possono essere restituiti. Ho impostato in modo esplicito la consistenza di lettura del datastore su strong nel mio jdoconfig.xml.

<?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+eventuale+consistenza di coerenza in "consistenza finale" in base all'aspetto. –

+0

@PaulCollingwood Ho impostato la coerenza di lettura del datastore su STRONG. HariShankar

+0

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

risposta

2

Ho un suggerimento, tuttavia non ti piacerà: usa esclusivamente API di basso livello e dimentica JDO/JPA quando usi GAE.

Proprio come @asp ha detto, ottenere ID dovrebbe essere fortemente coerente, tuttavia il plug-in GAE JDO mi sembra in errore. Sfortunatamente, la migrazione verso JPA non è stata di aiuto nel mio caso (più qui: JDO transactions + many GAE instances = overriding data). Inoltre, se annoto qualsiasi classe come @PersistenceAware, Eclipse impazzisce e migliora le classi nel ciclo infinito. Inoltre, ho riscontrato molti problemi durante l'utilizzo della classe @PersistenceCapable con la classe e il caching incorporati (senza che la memorizzazione nella cache funzionasse correttamente).

Bene, il punto è, penso che sarà molto più veloce con API di basso livello - sai esattamente cosa sta succedendo e sembra funzionare come previsto. Puoi trattare Entity come una mappa, con un po 'di codice wrapping autodidatta sembra un'alternativa abbastanza interessante. Ho eseguito alcuni test e con API di basso livello li ho passati senza problemi, mentre il passaggio con JDO/JPA non era possibile. Sono nel bel mezzo della migrazione della mia intera applicazione da JDO a API di basso livello. Richiede molto tempo, ma meno di aspettare indefinitamente per qualche soluzione magica o bugfix dal team GAE.

Inoltre, mentre scrivevo GAE JDO mi sentivo ... da solo. Se hai un problema con java, o anche con Android, un migliaio di altre persone hanno già avuto questo problema, ti hanno chiesto informazioni su StackOverflow e ottenuto tonnellate di soluzioni valide. Qui sei tutto da solo, quindi utilizza l'API di livello più basso possibile e sarai sicuro che cosa sta succedendo. Anche se la migrazione sembra spaventosa e dispendiosa in termini di tempo, credo che perderà meno tempo a migrare a API di basso livello piuttosto che a gestire GAE JDO/JPA. Non scrivo per pizzicare la squadra che sviluppa GAE JDO/JPA o per offenderli, sono sicuro che fanno del loro meglio. Ma:

  1. non c'è così tante persone che utilizzano GAE confronto con, consente di dire, Android o Java in generale

  2. Utilizzando GAE JDO/JPA con istanze multiple del server non è così semplice e lineare, come si penserei. Lo sviluppatore come me vuole fare il suo lavoro al più presto, vedere qualche esempio, leggere un po 'di documentazione - non studiare tutto in dettaglio, leggere un breve tutorial e lo sviluppatore ha un problema, vorrebbe condividerlo su StackOverflow e ricevi un aiuto rapido. È facile ottenere aiuto se fai qualcosa di sbagliato su Android, non importa se è complicato o è un errore facile. Non è così facile con GAE JDO/JPA. Ho dedicato molto più tempo agli articoli GAE JDO, alle esercitazioni e alla documentazione di quanto mi sarebbe piaciuto, e non sono riuscito a fare ciò che volevo, anche se sembrava piuttosto semplice. Se ho appena usato API di basso livello e non ho provato a prendere una scorciatoia con JDO (sì, pensavo che JDO mi avrebbe salvato il tempo), sarebbe stato molto, molto più veloce.

  3. Google si concentra su Python GAE molto più di Java. In molti articoli destinati a tutti gli spettatori, ci sono solo codice Python e suggerimenti, esempi rapidi qui: http://googlecloudplatform.blogspot.com/2013/12/best-practices-for-app-engine-memcache.html o qui: https://cloud.google.com/developers/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/. L'ho notato anche prima di iniziare lo sviluppo, ma volevo condividere del codice con il mio client Android, quindi ho scelto Java. Anche se ho un solido background Java e anche che ora condivido del codice, se potessi tornare indietro nel tempo e scegliere di nuovo, scegliere Python ora.

Ecco perché ritengo sia meglio utilizzare solo i metodi più basilari per accedere e manipolare i dati.

Buona fortuna, ti auguro tutto il meglio.

+0

Ho provato le operazioni di recupero utilizzando l'API di basso livello. Funziona bene. Il resto delle operazioni usa ancora JDO. Non sono sicuro se ciò causerà ulteriori problemi. – HariShankar

4

Se si utilizza il datastore l'Alto replica, l'impostazione della politica di lettura non garantisce che tutte le letture sono fortemente coerenti, quelli funzionano solo per le query antenato. Dalla documentazione;

L'API consente inoltre di impostare in modo esplicito un criterio di coerenza forte, ma questa impostazione non avrà alcun effetto pratico, poiché le query non di antenato sono sempre coerenti, indipendentemente dalla politica.

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

Si prega di dare un'occhiata al documento sulla Structuring Data for Strong Consistency, l'approccio preferito è al livello di caching per servire i dati.

Ho notato che stai utilizzando get ID, non è sicuro, ma "get by key" dovrebbe essere fortemente coerente anche per datastore HR (reference), puoi provare a cambiarlo per interrogare in base alla chiave? La chiave è costruita usando l'id e il tipo di entità e ascendenza.

Problemi correlati