Почему движок приложения выставляет мне меньше счетов, когда приведенный ниже код включен в транзакцию?

Я проверял это несколько раз, используя appstats. Когда приведенный ниже код НЕ включен в транзакцию, JDO выполняет две операции чтения хранилища данных и одну запись, 3 RPC, по цене 240. Не только в первый раз, каждый раз, даже если он обращается к одной и той же записи каждый раз, поэтому вытащить его из кеша. Однако когда я заключаю код в транзакцию, как указано выше, код создает 4 RPC: начать транзакцию, получить, положить и зафиксировать - из них только Get получает счет как чтение хранилища данных, поэтому общая стоимость составляет 70.

Если он вытаскивает его из кэша, почему он выставляет счет только за чтение? Казалось бы, это будет выставлять счет за запись, а не за чтение. Может ли ядро ​​приложения выставлять мне ту же сумму за нетранзакционные операции чтения из кэша, что и за чтение из хранилища данных? Зачем?

Это код транзакции WITH:

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 ответ

С транзакцией, PersistenceManager может знать, что кэши действительны на протяжении обработки этого кода. Без транзакции она не может (она не знает, произошло ли какое-то другое действие за ее спиной и что-то изменило) и поэтому должна проверять содержимое кэша по таблицам БД. Каждый раз, когда он проверяет, он должен создать транзакцию для этого; это особенность самого интерфейса БД, когда к любому действию, не входящему в транзакцию (с некоторыми исключениями для БД), автоматически добавляется транзакция.

В вашем случае вы все равно должны иметь транзакцию, потому что вы хотите иметь согласованное представление базы данных во время обработки. Без этого mapData может быть изменено другой операцией, пока вы работаете над ней, и эти изменения будут молча потеряны. Это было бы плохо. (Ну, наверное.) Транзакции - это лекарство.

(Вам также следует изучить использование AOP для управления переносом транзакций; это невероятно проще, чем каждый раз самостоятельно писать весь этот код управления транзакциями. OTOH, это может значительно усложнить развертывание до тех пор, пока вы не сделаете все правильно, поэтому я не могу понять, следуя этому совету…)

Другие вопросы по тегам