当以下代码包含在事务中时,为什么app引擎会减少对我的收费?

时间:2012-12-03 13:27:41

标签: java google-app-engine jdo datanucleus appstats

我已经使用appstats多次验证了这一点。当以下代码未包装在事务中时,JDO执行两次数据存储读取和一次写入,3次RPC,成本为240.不仅是第一次,每次,即使每次都访问相同的记录因此应该从缓存中拉出来。但是,当我在上面的事务中包装代码时,代码生成4个RPC:begin transaction,get,put和commit - 这些只有Get被记为数据存储读取,所以总成本是70。

如果它从缓存中提取它,为什么它只会为读取收费?它似乎会为写入而不是读取而收费。对于非事务性缓存读取,app引擎可能会为数据存储区读取计算相同的金额吗?为什么?

这是代码WITH transaction:

PersistenceManager pm = PMF.getManager();
Transaction tx = pm.currentTransaction();
String responsetext = "";
try {
  tx.begin();
  Key userkey = obtainUserKeyFromCookie();
  User u = pm.getObjectById(User.class, userkey);
  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
  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);

这是没有交易的代码:

PersistenceManager pm = PMF.getManager();
String responsetext = "";
try {
  Key userkey = obtainUserKeyFromCookie();
  User u = pm.getObjectById(User.class, userkey);
  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
  responsetext = "OK";
} catch (Exception e) {
  // log e
  responsetext = "ERROR";
} finally {
  pm.close();
}
resp.getWriter().println(responsetext);

1 个答案:

答案 0 :(得分:2)

通过事务,PersistenceManager可以知道缓存在整个代码处理过程中是有效的。如果没有事务,它就不能(它不知道是否有其他操作在其后面进行并且更改了事物),因此必须根据数据库表验证缓存的内容。每次检查时,都需要创建一个事务来执行此操作;这是数据库接口本身的一个特性,其中任何不在事务中的操作(具有一些特定于数据库的异常)将自动添加事务。

在您的情况下,您应该有一个事务,因为您希望在进行处理时拥有一致的数据库视图。如果没有这个,mapData可能会被另一个操作修改,而你正在处理它,那些修改将会无声地丢失。那会很糟糕。 (好吧,可能。)交易是治愈方法。

(您还应该考虑使用AOP来管理事务包装;这比每次自己编写所有事务管理代码要容易得多.OTOH,它可以为部署增加很多复杂性,直到您把事情做好,所以我可以理解不遵循这条建议......)