Je suis l'aide de JDO 2.3 sur app engine. J'ai été en utilisant le Maître/Esclave de la banque de données pour les tests locaux et récemment basculé à l'aide de la DRH de la banque de données pour les tests locaux, et des parties de l'une de mes applications sont de rupture (ce qui est à prévoir). Une partie de l'application, la rupture est l'endroit où il envoie beaucoup de écrit rapidement - c'est à cause de la 1-deuxième limite de chose, c'est de la faute de avec en même temps une modification de l'exception.
Ok, donc c'est également à prévoir, donc, j'ai le navigateur de nouvelle tentative de l'écrit à nouveau plus tard quand ils ne parviennent pas (peut-être pas le meilleur hack mais je suis juste en train de le faire rapidement).
Mais une chose étrange qui se passe. Certains de l'écrit qui doit être réussir (ceux qui NE sont PAS les modifications simultanées exception) sont également défaut, même si la phase de validation est terminée et que la requête retourne mon code de succès. Je peux le voir dans le journal que le retenté les demandes de travail sont d'accord, mais ces autres demandes qui semblent avoir commis sur le premier essai sont, je suppose, jamais "appliquées". Mais de ce que j'ai lu à propos de les Appliquer phase, écrit de nouveau à la même entité doit forcer l'appliquer... mais il ne le fait pas.
Le Code qui suit. Certaines choses sont à noter:
- Je suis d'essayer d'utiliser automatique JDO la mise en cache. C'est donc là que JDO utilise memcache sous les couvertures. Cela ne fait pas travailler à moins que vous enveloppez le tout dans une transaction.
- toutes les demandes sont à faire est de lire une chaîne de caractères de l'entité, la modification d'une partie de la chaîne, et la sauvegarde de cette chaîne à l'entité. Si ces demandes n'étaient pas dans les transactions, vous feriez bien sûr la "sale lire" problème. Mais avec des transactions, l'isolation est censé être au niveau de "serializable" donc je ne vois pas ce qui se passe ici.
- l'entité en cours de modification est une racine de l'entité (et non pas dans un groupe)
- J'ai de la croix-transactions du groupe activé
Le code (c'est une version simplifiée):
PersistenceManager pm = PMF.getManager();
Transaction tx = pm.currentTransaction();
String responsetext = "";
try {
tx.begin();
// I have extra calls to "makePersistent" because I found that relying
// on pm.close didn't always write the objects to cache, maybe that
// was only a DataNucleus 1.x issue though
Key userkey = obtainUserKeyFromCookie();
User u = pm.getObjectById(User.class, userkey);
pm.makePersistent(u); // to make sure it gets cached for next time
Key mapkey = obtainMapKeyFromQueryString();
// this is NOT a java.util.Map, just FYI
Map currentmap = pm.getObjectById(Map.class, mapkey);
Text mapData = currentmap.getMapData(); // mapData is JSON stored in the entity
Text newMapData = parseModifyAndReturn(mapData); // transform the map
currentmap.setMapData(newMapData); // mutate the Map object
pm.makePersistent(currentmap); // make sure to persist so there is a cache hit
tx.commit();
responsetext = "OK";
} catch (JDOCanRetryException jdoe) {
// log jdoe
responsetext = "RETRY";
} catch (Exception e) {
// log e
responsetext = "ERROR";
} finally {
if (tx.isActive()) {
tx.rollback();
}
pm.close();
}
resp.getWriter().println(responsetext);
Mise à JOUR: je suis assez sûr que je sais pourquoi ce qui se passe, mais je vais toujours de l'attribution de la prime à tous ceux qui peuvent le confirmer.
Fondamentalement, je pense que le problème est que les transactions ne sont pas vraiment mis en œuvre dans la version locale de la banque de données. Références:
https://groups.google.com/forum/?fromgroups=#!topic/google appengine-java/gVMS1dFSpcU https://groups.google.com/forum/?fromgroups=#!topic/google appengine-java/deGasFdIO-M https://groups.google.com/forum/?hl=en&fromgroups=#!msg/google-appengine-java/4YuNb6TVD6I/gSttMmHYwo0J
Parce que les transactions ne sont pas mises en œuvre, la restauration est essentiellement un no-op. Donc, je suis un sale lire lors de deux opérations d'essayer de modifier l'enregistrement en même temps. En d'autres termes, Un lit les données et B lit les données en même temps. Une tentative pour modifier les données, et B tente de modifier une partie différente des données. Un écrit à la banque de données, puis B écrit, oblitérer Un modifications. Alors B est "annulée" par app engine, mais depuis les restaurations sont un no-op lors de l'exécution sur le magasin de données local, les B des changements de séjour, et ne le font pas. En attendant, puisque B est le thread qui a déclenché l'exception, le client tentatives B, mais n'essaie pas de A (car a est soi-disant la transaction qui a réussi).