如何在Redis中實現事務
事務介紹
事務(Transaction) ,是指作為單個邏輯工作單元執行的一系列操作。事務必須滿足ACID原則(原子性、一致性、隔離性和持久性)。
簡單來說,事務可能包括1~N條命令,當這些命令被作為事務處理時,將會順序執行這些命令直到完成,并返回結果,如果中途有命令失敗,則會回滾所有操作。
舉個例子:
-
我們到銀行ATM機取一筆錢,我們的操作可能是如下:
-
插卡(輸入密碼)
-
輸入要取的金額
-
ATM吐鈔
后臺在你的戶頭上扣掉相應金額
整個操作是一個順序,不可分割的整體。上一步完成后才會執行下一步,如果ATM沒吐鈔卻扣了用戶的錢,銀行可是要關門了。
Redis中的事務
先來看一下事務相關的命令
命令原型 | 命令描述 |
MULTI | 用于標記事務的開始,其后執行的命令都將被存入命令隊列,直到執行EXEC時,這些命令才會被原子的執行。 |
EXEC | 執行在一個事務內命令隊列中的所有命令,同時將當前連接的狀態恢復為正常狀態,即非事務狀態。如果在事務中執行了WATCH命令,那么只有當WATCH所監控的Keys沒有被修改的前提下,EXEC命令才能執行事務隊列中的所有命令,否則EXEC將放棄當前事務中的所有命令。 |
DISCARD | 回滾事務隊列中的所有命令,同時再將當前連接的狀態恢復為正常狀態,即非事務狀態。如果WATCH命令被使用,該命令將UNWATCH所有的Keys。 |
WATCH key [key ...] | 在MULTI命令執行之前,可以指定待監控的Keys,然而在執行EXEC之前,如果被監控的Keys發生修改,EXEC將放棄執行該事務隊列中的所有命令。 |
UNWATCH | 取消當前事務中指定監控的Keys,如果執行了EXEC或DISCARD命令,則無需再手工執行該命令了,因為在此之后,事務中所有被監控的Keys都將自動取消。 |
和關系型數據庫中的事務相比,在Redis事務中如果有某一條命令執行失敗,其后的命令仍然會被繼續執行。
我們可以通過MULTI命令開啟一個事務,有關系型數據庫開發經驗的人可以將其理解為 BEGIN TRANSACTION 語句。在該語句之后執行的命令都將被視為事務之內的操作,最后我們可以通過執行 EXEC/DISCARD 命令來提交/回滾該事務內的所有操作。這兩個Redis命令可被視為等同于關系型數據庫中的 COMMIT/ROLLBACK 語句。
在事務開啟之前,如果客戶端與服務器之間出現通訊故障并導致網絡斷開,其后所有待執行的語句都將不會被服務器執行。然而如果網絡中斷事件是發生在客戶端執行 EXEC 命令之后,那么該事務中的所有命令都會被服務器執行。
當使用Append-Only模式時,Redis會通過調用系統函數write將該事務內的所有寫操作在本次調用中全部寫入磁盤。然而如果在寫入的過程中出現系統崩潰,如電源故障導致的宕機,那么此時也許只有部分數據被寫入到磁盤,而另外一部分數據卻已經丟失。Redis服務器會在重新啟動時執行一系列必要的一致性檢測,一旦發現類似問題,就會立即退出并給出相應的錯誤提示。此時,我們就要充分利用Redis工具包中提供的redis-check-aof工具,該工具可以幫助我們定位到數據不一致的錯誤,并將已經寫入的部分數據進行回滾。修復之后我們就可以再次重新啟動Redis服務器了。
樣例
@Test
public void test2Trans() {
Jedis jedis = new Jedis("localhost");
long start = System.currentTimeMillis();
Transaction tx = jedis.multi();
for (int i = 0; i < 100000; i++) {
tx.set("t" + i, "t" + i);
}
List<Object> results = tx.exec();
long end = System.currentTimeMillis();
System.out.println("Transaction SET: " + ((end - start)/1000.0) + " seconds");
jedis.disconnect();
}
得到事務結果result之后,可以檢查當中是否有非OK的返回值,如果存在則說明中間執行錯誤,可以使用 DISCARD 來回滾執行結果。
WATCH命令
WATCH 為 MULTI 執行之前的某個Key提供監控(樂觀鎖)的功能,如果Key的值變化了,就會放棄事務的執行。
當事務 EXEC 執行完成之后,就會自動 UNWATCH 。
Session 1 | Session 2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </tr> | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
|