0

UserA et UserB changent objectA.filedA objectA.filedB respectivement et en même temps. Parce qu'ils ne changent pas le même champ, on pourrait penser qu'il n'y a pas de chevauchement. Est-ce vrai? ou l'implémentation de pm.makePersistnace() remplace réellement l'objet entier ... bon à savoir ...GAE mettre à jour différents champs de la même entité

Répondre

1

Est-ce que c'est ce que vous envisagez de passer?

  1. Alice récupère l'objet. {a = 1, b = "Foo"}
  2. Bob récupère l'objet. {a = 1, b = "Foo"}
  3. Alice modifie l'objet, en changeant b. {a = 1, b = "Bar"}
  4. Bob modifie l'objet, en changeant a. {a = 2, b = "Foo"}
  5. Alice conserve sa copie de l'objet. {a = 1, b = "Bar"}
  6. Bob conserve sa copie de l'objet. {A = 2, b = « Foo »}

la copie de Bob de l'objet remplacera la copie dans le datastore, parce qu'il est persistant son objet entier, non seulement son ensemble de champs modifiés. Ou, en général, celui qui persiste le dernier a son objet entier persisté dans le magasin de données.

Vous pouvez résoudre ce problème en exécutant chacune de leurs opérations get-set-and-persistent dans une transaction. Les transactions App Engine n'empêchent pas l'extraction ou la modification de l'intégralité de l'objet localement, elles empêchent simplement la persistance d'autres utilisateurs. Donc:

  1. Alice récupère l'objet dans une transaction. {a = 1, b = "Foo"}
  2. Bob récupère l'objet dans une transaction. {a = 1, b = "Foo"}
  3. Alice modifie l'objet, en changeant b. {a = 1, b = "Bar"}
  4. Bob modifie l'objet, en changeant a. {a = 2, b = "Foo"}
  5. Alice essaie de persister l'objet, mais ne peut pas, car Bob l'a ouvert dans une transaction. Une exception sera levée, qu'Alice attrapera en terminant sa transcation et en réessayant ...
  6. Bob persiste l'objet, sans problème, car Alice a terminé sa transaction {a = 2, b = "Foo"}
  7. Alice réessaie sa transaction en la récupérant à nouveau. {a = 2, b = "Foo"}
  8. Alice modifie l'objet, en changeant b. {a = 2, b = "Bar"}
  9. Alice persiste l'objet, et cela fonctionne parce que personne d'autre n'a une transaction ouverte. {a = 2, b = "Bar"}

Je ne suis pas absolument sûr quel utilisateur obtiendra l'exception, mais tant qu'ils seront prêts à réessayer quand ils le verront, ils seront à la fois capable de faire leurs changements à l'objet et les persister, finalement. Ce numéro est appelé Optimistic Locking.

+0

Vous pourriez vouloir reconsidérer en utilisant « id » et 'nom' - ils sont tous les deux des termes réservés dans App Engine, et ne sont pas modifiables. –

+0

Excellente recommandation. Renommé en a et b. Je vais aussi renommer l'utilisateur A et l'utilisateur B à Alice et Bob, pour éviter encore plus de confusion. –

0

Merci pour votre réponse. Dommage que l'implémentation de makePersistence() consiste à écrire l'objet WHOLE dans la banque de données et pas seulement dans les champs qui ont été modifiés. Ce fait oblige réellement toute mise à jour d'objet partagé dans GAE pour utiliser une transaction en tant que règle. En outre plus - dans de tels cas, vous devez implémenter le "mécanisme de tentative" comme une exception dans la transaction peut se produire.

Alors ... mettre à jour un objet partagé GAE doit toujours avoir ces extras:

  • le faire dans une transaction
  • mettre en place un mécanisme de nouvelle tentative

La plupart des exemples de Google dans leur site ne sont en fait pas en tenir compte. Comme s'ils sont en supposant que la plupart des applications ne seront pas utilisées objets partagés

Par exemple (http://code.google.com/appengine/docs/java/datastore/creatinggettinganddeletingdata.html):

public void updateEmployeeTitle(User user, String newTitle) { 
    PersistenceManager pm = PMF.get().getPersistenceManager(); 
    try { 
     Employee e = pm.getObjectById(Employee.class, user.getEmail()); 
     if (titleChangeIsAuthorized(e, newTitle) { 
      e.setTitle(newTitle); 
     } else { 
      throw new UnauthorizedTitleChangeException(e, newTitle); 
     } 
    } finally { 
     pm.close(); 
    } 
} 

OU:

public void updateEmployeeTitle(Employee e, String newTitle) { 
    if (titleChangeIsAuthorized(e, newTitle) { 
     e.setTitle(newTitle); 
     PersistenceManager pm = PMF.get().getPersistenceManager(); 
     try { 
      pm.makePersistent(e); 
     } finally { 
      pm.close(); 
     } 
    } else { 
     throw new UnauthorizedTitleChangeException(e, newTitle); 
    } 
} 
+0

Ils ne gèrent pas non plus 'OverQuotaException's ou' CapabilityDisabledException's, mais c'est probablement juste parce que cela rendrait l'exemple trop complexe pour être utile. Et la vérité est, la plupart des applications n'auront jamais ces problèmes parce que la plupart des applications ne seront pas si fortement utilisées que les modifications simultanées sont un problème. Certaines applications n'éditent même pas du tout les entités existantes, seulement les créent et les affichent. Votre application semble être celle qui doit en tenir compte, c'est donc une bonne chose que vous l'ayez examiné. –

+1

Aussi, ce n'est généralement pas une bonne idée de répondre à votre propre question avec une discussion sur la question. C'est ce que les commentaires sont pour, soit sur votre question, ou sur la réponse. –

+0

mais le code n'apparaît pas bien et difficile à lire – bach

Questions connexes