没有交易
问题描述:
我经历了碎片化的Java谷歌的AppEngine分片专柜柜台Java示例: http://code.google.com/appengine/articles/sharding_counters.html没有交易
我有一个关于增量法的实施问题。在python中,它明确地包装了get()并在事务中增加。在Java示例中,它只是检索并设置它。我不确定我完全理解数据存储和事务,但似乎关键更新部分应该包装在数据存储事务中。我错过了什么吗?
原始代码:
public void increment() {
PersistenceManager pm = PMF.get().getPersistenceManager();
Random generator = new Random();
int shardNum = generator.nextInt(NUM_SHARDS);
try {
Query shardQuery = pm.newQuery(SimpleCounterShard.class);
shardQuery.setFilter("shardNumber == numParam");
shardQuery.declareParameters("int numParam");
List<SimpleCounterShard> shards =
(List<SimpleCounterShard>) shardQuery.execute(shardNum);
SimpleCounterShard shard;
// If the shard with the passed shard number exists, increment its count
// by 1. Otherwise, create a new shard object, set its count to 1, and
// persist it.
if (shards != null && !shards.isEmpty()) {
shard = shards.get(0);
shard.setCount(shard.getCount() + 1);
} else {
shard = new SimpleCounterShard();
shard.setShardNumber(shardNum);
shard.setCount(1);
}
pm.makePersistent(shard);
} finally {
pm.close();
}
}
}
事务代码(我相信你需要在一个事务中运行该下并发事务出示担保正确性?):
public void increment() {
PersistenceManager pm = PMF.get().getPersistenceManager();
Random generator = new Random();
int shardNum = generator.nextInt(NUM_SHARDS);
try {
Query shardQuery = pm.newQuery(SimpleCounterShard.class);
shardQuery.setFilter("shardNumber == numParam");
shardQuery.declareParameters("int numParam");
List<SimpleCounterShard> shards =
(List<SimpleCounterShard>) shardQuery.execute(shardNum);
SimpleCounterShard shard;
// If the shard with the passed shard number exists, increment its count
// by 1. Otherwise, create a new shard object, set its count to 1, and
// persist it.
if (shards != null && !shards.isEmpty()) {
Transaction tx = pm.currentTransaction();
try {
tx.begin();
//I believe in a transaction objects need to be loaded by ID (can't use the outside queried entity)
Key shardKey = KeyFactory.Builder(SimpleCounterShard.class.getSimpleName(), shards.get(0).getID())
shard = pm.getObjectById(SimpleCounterShard.class, shardKey);
shard.setCount(shard.getCount() + 1);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
} else {
shard = new SimpleCounterShard();
shard.setShardNumber(shardNum);
shard.setCount(1);
}
pm.makePersistent(shard);
} finally {
pm.close();
}
}
答
这部分直出的文档中表明您完全需要交易:
http://code.google.com/appengine/docs/java/datastore/transactions.html#Uses_For_Transactions
此示例演示了事务的一种用法:使用相对于其当前值的新属性值更新实体。
Key k = KeyFactory.createKey("Employee", "k12345");
Employee e = pm.getObjectById(Employee.class, k);
e.counter += 1;
pm.makePersistent(e);
这需要一个事务,因为该值可以通过这个代码后的另一用户进行更新的获取对象,但在此之前将其保存被修改的对象。如果没有交易,用户的请求将在其他用户更新之前使用计数器的值,并且保存将覆盖新值。通过交易,应用程序会被告知其他用户的更新。如果实体在事务期间更新,那么事务将失败并出现异常。应用程序可以重复交易以使用新数据。
它非常接近分片示例正在做的事情,和您一样,我无法找到分片计数器会有所不同的任何原因。
我在Appengine问题跟踪器上创建了一个公开问题: http://code.google.com/p/googleappengine/issues/detail?id=3778 – Dougnukem 2010-09-24 19:18:12
@Dougnukem - 非常好。如果可以的话,我会再次提出您的问题,努力将反馈意见反馈给项目以改进它。我提出了其他问题之一:-) – 2010-09-24 19:39:21