簡體   English   中英

Java Google Appengine分片計數器,無需事務處理

[英]Java Google Appengine sharded counters without transactions

我正在使用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);

這需要進行事務處理,因為在此代碼獲取對象之后但在保存修改后的對象之前,其他用戶可能會更新該值。 如果沒有事務,則用戶的請求將在其他用戶更新之前使用counter的值,並且保存將覆蓋新值。 通過事務,該應用程序將被告知其他用戶的更新。 如果在事務期間更新實體,則事務將失敗,並發生異常。 應用程序可以重復交易以使用新數據。

它與分片示例的操作非常接近,並且像您一樣,我無法找到分片計數器不同的任何原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM