没有交易

问题描述:

我经历了碎片化的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); 

这需要一个事务,因为该值可以通过这个代码后的另一用户进行更新的获取对象,但在此之前将其保存被修改的对象。如果没有交易,用户的请求将在其他用户更新之前使用计数器的值,并且保存将覆盖新值。通过交易,应用程序会被告知其他用户的更新。如果实体在事务期间更新,那么事务将失败并出现异常。应用程序可以重复交易以使用新数据。

它非常接近分片示例正在做的事情,和您一样,我无法找到分片计数器会有所不同的任何原因。

+1

我在Appengine问题跟踪器上创建了一个公开问题: http://code.google.com/p/googleappengine/issues/detail?id=3778 – Dougnukem 2010-09-24 19:18:12

+0

@Dougnukem - 非常好。如果可以的话,我会再次提出您的问题,努力将反馈意见反馈给项目以改进它。我提出了其他问题之一:-) – 2010-09-24 19:39:21