11. SDR 事務

我們知道Redis 是支持弱事務的, Redis 中的事務只能保證命令在同一個連接中執行,當發生異常後並不會進行事務回滾. SDR 對這種弱事務也提供了支持。 除了支持redis-cli 客戶端的multi, exec, discard 命令之外, SDR 還支持使用聲明式註解@Transaction 註解類強制開啓事務, 但筆者並未使用過,如果有興趣,可以自行嘗試。

1. SDR 事務

1.1 SDR 事務特點

  • 事務中所有命令, 在同一連接中執行
  • 事務中的所有命令,在執行exec方法時,纔開始依次執行
  • 事務中所有命令都會執行,縱使中間有命令報錯,也不會終止後面的命令執行
  • 事務中發生異常時,已執行的命令不會發生回滾。

1.2 相關API

方法簽名 方法描述
void multi() 開啓事務
List exec() 執行事務, 返回每條命令的返回結果
void discard() 丟棄事務

1.3 @Transaction 強制開啓事務

SDR 中默認RedisTemplate是關閉事務,可以配置自定義RedisTemplate時,設置強制開啓事務 setEnableTransactionSupport(true). 此方法會強制當前RedisTemplate 綁定的RedisConnection在當前線程中強制開啓事務, 當事務結束時,若沒有異常則自動觸發exec方法提交事務,否則自動觸發discard方法丟棄事務.

1.4 事務和pipeline 的區別

雖然事務和pipeline看起來很相似,都可以批量執行命令,但是還是有本質性的不同的。

  • 相同點:
    1. pipeline 和 事務都是在同一連接中執行的, 減少了多次TCP連接創建銷燬的實際,提高了性能
    2. pipeline 和 事務當執行命令過程出現異常時均不會終止後面的命令運行
  • 不同點:事務是當執行exec方法時, 統一開始執行命令; 當執行ops的相關命令時,並非真正的執行. 而pipeline則時,執行ops 命令時就真正開始執行命令.

2. API 測試

2.1 提交事務exec

  • 執行測試用例前,先清空redis數據庫或刪除redis中key爲 A,B,C 的key-value
  • 從控制檯輸出可以看出, 雖然執行第二天命令失敗了,但是並沒有拋出異常,也沒有終止剩餘命令執行
@Test
public void test_exec(){

    List<Object> txResults =  stringRedisTemplate.execute(new SessionCallback<List<Object>>() {
        @Override
        public List<Object> execute(RedisOperations operations) throws DataAccessException {
            // 開啓事務
            operations.multi();

            ValueOperations ops = operations.opsForValue();
            ops.set("A", "aaaa");
            ops.setIfPresent("B","aaa");
            ops.set("C", "cccc");

            // 執行事務
            return operations.exec();
        }
    });

    // 遍歷返回結果
    for (Object txResult : txResults) {
        System.out.println(txResult);
    }
    
    /* 控制檯輸出
        true
        false
        true
    */
}

2.2 取消事務discard

  • discard 會取消事務中的命令,並丟棄
  • 測試之後,發現redis中並沒有A, B, C三個key, 這說明雖然調用了ops.set方法, 但是命令並沒有執行.
@Test
public void test_discard(){

    List<Object> txResults =  stringRedisTemplate.execute(new SessionCallback<List<Object>>() {
        @Override
        public List<Object> execute(RedisOperations operations) throws DataAccessException {
            // 開啓事務
            operations.multi();

            ValueOperations ops = operations.opsForValue();
            ops.set("A", "aaaa");
            ops.set("B","aaa");
            ops.set("C", "cccc");

            // 取消事務
            operations.discard();

            return null;
        }
    });
    System.out.println("txResults:" + txResults);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章