eee*_*aii 28 java google-app-engine memcached jdo
我在app引擎上使用JDO 2.3.我使用Master/Slave数据存储区进行本地测试,最近切换到使用HRD数据存储区进行本地测试,我的部分应用程序正在破坏(这是预期的).正在破坏的应用程序的一部分是快速发送大量写入的地方 - 这是因为1秒限制的事情,它失败了并发修改异常.
好吧,所以这也是预料之中的,所以我让浏览器在失败后再次重试写入(可能不是最好的黑客,但我只是想让它快速运行).
但是一件奇怪的事情正在发生.即使提交阶段完成且请求返回我的成功代码,一些应该成功的写入(不会获得并发修改异常的写入)也会失败.我可以从日志中看到重试的请求工作正常,但是我猜这些似乎在第一次尝试时提交的其他请求从未"应用".但是从我读到的关于Apply阶段的内容来看,再次写入同一个实体应该强制应用......但事实并非如此.
代码如下.有些事情需要注意:
相关代码(这是简化版):
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);
Run Code Online (Sandbox Code Playgroud)
更新:我很确定我知道为什么会发生这种情况,但我仍会将奖金奖励给任何可以确认的人.
基本上,我认为问题是事务并没有真正在本地版本的数据存储中实现.参考文献:
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
由于事务未实现,因此回滚本质上是一种无操作.因此,当两个事务试图同时修改记录时,我得到一个脏读.换句话说,A读取数据,B同时读取数据.尝试修改数据,B尝试修改数据的不同部分.写入数据存储区,然后B写入,消除A的更改.然后B由应用引擎"回滚",但由于在本地数据存储上运行时回滚是无操作,因此B的更改保持不变,而A则不然.同时,由于B是抛出异常的线程,客户端重试B,但不重试A(因为A应该是成功的事务).
也许对你来说是个坏消息,我离开了 JDO,我正在使用 Objectify,并且在某些地方直接使用 datanucleus。我可以完美地控制我的坚持,这是一个性能和设计更好的选择(如果你从长远来看)。
由于数据库是 no-sql,因此针对 JPA、JDO 和标准假设进行了结构更改:
使用本机 datanucleus API,您可以执行标准 JPA 甚至 Objectify 中没有的操作:我使用的示例是动态创建列
GAE 中不存在事务,有些东西有时看起来像事务(实体组)。因此,使用原生 API 将避免你做这种不可预见的体操。
尝试用操纵杆驾驶汽车是可行的,但肯定有新的东西需要学习。我认为以原生方式学习是值得的
归档时间: |
|
查看次数: |
583 次 |
最近记录: |