我将 GAE SDK 1.8.9 与 Java 1.7(内部版本 45)一起使用。对于数据存储,我使用的是 Datanucleus JDO v2。我已经将代码部署到生产环境中,为每个新的“订单”请求更新计数器,并且出现了一些一致性问题,我认为这些问题与在几秒钟内处理来自不同服务器的请求有关。数据存储实体由一个唯一键(由我的应用程序生成)、几个日期字段和一个 orderId 计数器组成。数据存储区中只有少数这些实体。
这是我的逻辑的一个子集......
keyId 是 StoreWrapper 类中 String 类型的实例变量
StoreWrapper 类中的 newOrderId() 方法应该在数据存储区中获取所需的 Store 实体(基于 keyId),增加实体的 orderId 值,使用更新后的值将实体更新回数据存储区,最后返回更新后的值 (或 0 如果发生错误)给调用者。获取、递增和更新都发生在使用事务的 .begin() 和 .commit() 方法的 JDO 事务中。
Store 类中的 newOrderId() 方法只是增加 orderId 值(加上一些逻辑,以允许它在达到上限时翻转)。
公共 int newOrderId() { int orderId = 0;
PersistenceManager pm = PMF.get().getPersistenceManager();
Transaction tx = pm.currentTransaction();
Store tempStore = null;
try {
tx.begin(); // Use a transaction to modify value (read, update, write)
tempStore = pm.getObjectById(Store.class, keyId);
tempStore.newOrderId();
pm.makePersistent(tempStore); // Problem occurs regardless if this statement exists or not
tx.commit();
orderId = tempStore.getOrderId();
} catch (JDOObjectNotFoundException e) {
// Do new store stuff
...
} catch (JDOUserException e) {
System.out.println(e.getMessage());
} catch (JDODataStoreException e) {
System.out.println(e.getMessage());
} catch (JDOCanRetryException e) {
System.out.println(e.getMessage());
} catch (JDOOptimisticVerificationException e) {
System.out.println(e.getMessage());
} catch (JDOFatalException e) {
System.out.println(e.getMessage());
} catch (JDOException e) {
System.out.println(e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
if (tx.isActive())
tx.rollback();
pm.close();
}
return orderId;
}
当我在短时间内提交多个下订单请求时,我注意到订单的另一个数据存储中有重复的订单号。我的研究得出结论,当多个实例正在处理请求时会发生这种情况。在日志中,我可以看到每次发生这种情况时,重复的实例都是不同的。我的理解是实体组默认为根(考虑到实体的简单性质,这种情况就是这种情况,因为我在生成密钥时没有指定父级),但我无处可寻至于为什么行为表现得像“最终一致性”而不是“强一致性”。我已经为各种异常设置了几个捕获,但没有看到任何证据表明日志中发生了这些异常。我' 甚至将线程安全设置为“假”,因此每个实例只处理一个请求,并且仍然会发生。是否有一些设置必须设置为跨多个实例强制执行“强一致性”?