2014-02-09 65 views
3

我正在關注RetwisJ教程可用here。在這個我不認爲Redis交易實施。例如,在以下函數中,如果兩者之間發生某種異常,數據將保持不一致的狀態。 我想知道如何像下面的函數可以在春數據Redis的作爲一個單獨的事務來實現:如何以乾淨的方式在Spring Data Redis中實現事務?

public String addUser(String name, String password) { 
     String uid = String.valueOf(userIdCounter.incrementAndGet()); 

     // save user as hash 
     // uid -> user 
     BoundHashOperations<String, String, String> userOps = template.boundHashOps(KeyUtils.uid(uid)); 
     userOps.put("name", name); 
     userOps.put("pass", password); 
     valueOps.set(KeyUtils.user(name), uid); 

     users.addFirst(name); 
     return addAuth(name); 
    } 

這裏userIdCountervalueOpsusers在構造函數初始化。我在文檔(4.8節)中遇到過this,但我無法弄清楚如何將這個函數放入函數中,其中一些變量是在函數外初始化的(請不要告訴我必須在每個變量中初始化這些變量,每一個我需要交易的功能!)。

PS:還有什麼@Transaction註釋或事務管理器可用於Spring Data Redis?

更新:我試過使用MULTI,EXEC。這是我寫的代碼是另一個項目,但其在應用到這個問題,將是如下:

public String addMyUser(String name, String password) { 
     String uid = String.valueOf(userIdCounter.incrementAndGet()); 
     template.execute(new SessionCallback<Object>() { 
      @Override 
      public <K, V> Object execute(RedisOperations<K, V> operations) 
        throws DataAccessException { 
       operations.multi(); 
       getUserOps(operations, KeyUtils.uid(uid)).put("name", name); 
       getUserOps(operations, KeyUtils.uid(uid)).put("pass", password); 
       getValueOps(operations).set(KeyUtils.user(name), uid); 
       getUserList(operations, KeyUtils.users()).leftPush(name); 
       operations.exec(); 
       return null; 
      } 
     }); 
     return addAuth(name); 
    } 
    private ValueOperations<String, String> getValueOps(RedisOperations operations) { 
     return operations.opsForValue(); 
    } 
    private BoundHashOperations<String, String, String> getUserOps(RedisOperations operations, String key) { 
     return operations.boundHashOps(key); 
    } 
    private BoundListOperations<String, String> getUserList(RedisOperations operations, String key) { 
     return operations.boundListOps(key); 
    } 

請告知是否使用MULTI這種方式,EXEC建議還是不要。

回答

1

最多SD Redis的1.2,你將不得不使用TransactionSynchronisationManager

的snipplet上方,然後可能看起來像這樣照顧含有交易處理自己:

public String addUser(String name, String password) { 

    String uid = String.valueOf(userIdCounter.incrementAndGet()); 

    // start the transaction 
    template.multi(); 

    // register synchronisation 
    if(TransactionSynchronisationManager.isActualTransactionActive()) { 
     TransactionSynchronisationManager.registerSynchronisation(new TransactionSynchronizationAdapter()) { 

      @Override 
      public void afterCompletion(int status) { 
       switch(status) { 
        case STATUS_COMMITTED : template.exec(); break; 
        case STATUS_ROLLED_BACK : template.discard(); break; 
        default : template.discard(); 
       } 
      } 
     } 
    } 

    BoundHashOperations<String, String, String> userOps = template.boundHashOps(KeyUtils.uid(uid)); 
    userOps.put("name", name); 
    userOps.put("pass", password); 
    valueOps.set(KeyUtils.user(name), uid); 

    users.addFirst(name); 

    return addAuth(name); 
} 

請注意,多一次,讀操作也將成爲交易的一部分,這意味着您可能無法從Redis服務器讀取數據。 設置可能與上述不同,因爲您可能需要額外撥打WATCH。此外,您還必須處理多個回叫,不要多次發送MULTI和/或EXEC

即將發佈的1.3版Spring Data Redis將支持彈性管理的事務處理,並支持MULTi|EXEC|DISCARD,允許在事務同步處於活動狀態時執行讀取操作(在已有鍵上)。您可以通過設置template.setEnableTransactionSupport(true)將BUILD-SNAPSHOT旋轉並打開。

+0

嗨,從問這個問題已經很長時間了。由於沒有人回答,我想出瞭如何去做(在問題中更新)。但我不知道這是否是推薦的方式。是TransactionSynchronisationManager的路要走嗎?除此之外是否需要其他配置?我在我寫的代碼中發現的優點是,如果必須從Redis讀取數據,我可以使用'template',因此它不會成爲事務的一部分。 – sinu

+1

使用'SessionCallback'完全沒問題[參考](http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/redis.html#tx)),因爲這會將命令執行時所用的連接綁定到之後執行並釋放它。 'TransactionSynchronisationManager'或下一個版本1.3'template.setEnableTransactionSupport(true)'是用於處理多個對redis的調用,當外部事務處於活動狀態時,這些調用可能不在位置上。通常不需要直接與TSM進行交互。 –

相關問題