1. 程式人生 > >Reids基礎事務以及watch監控事務和回滾

Reids基礎事務以及watch監控事務和回滾

Redis也是有事務的
Redis執行事務的三個過程:

1.開啟事務 multi
2.命令進入佇列
3.執行事務 exec

如果要求在一個連線中,在spring會使用SessionCallback介面來處理。這是為了減少效能損耗

redis的基礎事務:

multi開啟事務,直到exec執行事務,期間的命令將以佇列形式存在,直到exec命令的出現,才會一次性發送佇列裡的命令去執行,執行過程中其他客戶端也不能再插入任何命令了。也可以直接discard回滾事務(取消了事務中的命令),到exec時已經沒有命令可以執行了。

注意開啟事務後,命令不會馬上執行,而是加入到佇列中,只有當執行事務exec的時候才會順序執行,其實還有一個watch命令,監聽某些鍵,當exec的時候他會檢測該鍵值有無發生變化,如果沒有則執行命令,否則回滾事務。

舉個例子:這裡用同一個連線操作Redis命令還有Lambda表示式(代替匿名類)
注意不知道為什麼,在idea中使用lambda表示式會出現紅色的下劃線提醒,但是可以執行,沒有問題……疑惑ing

 @Test
    public void xx() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        final RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
        SessionCallback sessionCallback = (SessionCallback)(RedisOperations ops) ->{
          ops.multi();//開啟事務
          ops.boundValueOps("key1").set("value1");
          String value =(String) ops.boundValueOps("key1").get();
          System.out.println(value);
          List list = ops.exec();//list儲存之前進入佇列的所有命令的結果
            value =(String) redisTemplate.opsForValue().get("key1");
            return value;
        };
        String value =(String) redisTemplate.execute(sessionCallback);
        System.out.println(value);
    }

輸出:

null
value1

第一個value輸出null,原因是此時命令只是被加入到佇列中,而咩有被執行,所有是null
第二個value已經執行完畢了
注意使用SessionCallback介面可以保證所有的命令都是通過一個Redis連結進行操作
如果想要得到Redis執行事務各個命令的結果可以使用List list = ops.exec();
**

再來探究下Redis的事務回滾:

事務回滾是為了保證資料的一致性性,要麼同時完成,要麼同時失敗。
Redis的事務回滾和資料庫有點不一樣。
Redis事務遇到命令格式正確而資料型別不正確:

multi
set key1 value1
set key2 value2
incr key1
del key2
exec

注意:incr是自增,命令加入到佇列的時候不會報錯,但是執行exec的時候,就會遇到型別錯誤(value1是字串而不是數字),而之前和之後的命令都會被執行,就本身不會執行。
如果是命令格式錯誤,那麼直接事務回滾。

結論:

執行事務命令的時候,命令入隊的時候Redis會檢測事務的命令是否正確,如果不正確,全部命令回滾,相當於什麼也沒有執行。如果命令不正確,但是操作資料結構有問題,那麼該命令執行錯誤,而其之前和之後的命令都會被正常執行。
所以對於一些重要操作,我們要檢測資料的正確性以保證事務的正確執行,避免資料不一致。

那為什麼redis要設定如此簡陋的事務呢?
當然是為了保證最重要的問題-----效能。

再來看看:watch命令監控事務。

watch命令可以決定事務是執行還是回滾。watch命令,監控某些鍵值對,當執行事務exec的時候,首先會判斷被watch命令監控的鍵值對前後是否發生變化,最後都會取消監控。所以watch是一次性消費的。
Redis在監控事務的時候參考了多執行緒的CAS(Compare And Swap),在資料高併發的操作中,這種機制也叫作樂觀鎖。但是有時候會存在ABA問題,即被監控的值變換為A-B-A,事務前後的值最終沒有變,但是過程中改變了,如果此時併發處理就會出現問題。
但是在Redis事務中,並不阻塞其他連線的併發,而只是通過比較watch監控的鍵值對去保證資料的一致性,可以再非阻塞的多執行緒環境中併發執行,不會產生ABA問題,因為就算修改被watch監控的值為原來的值,還是會認為他被修改過了,有點繞。舉個例子:
開啟一個客戶端:

./redis-cli               ./redis-cli 
set key1 value1                null
watch key1                     null
multi                          null
set key2 value2          set key1 value1
exec

返回結果(nil)
表示事務回滾了。