實現事務的方法 multi(開啟事務)+exec(提交)+discard(放棄事務)+watch(CAS樂觀鎖) lua指令碼
Redis事務的特點 事務中的所有方法串列執行,執行過程不會被其它client打斷; 事務是原子的,命令全執行,或全不執行,但是,Redis的原子性和關聯式資料庫的原子性不一致,Redis雖然能保證命令全執行,但是如果某條命令在執行時出錯,Redis會忽略它,繼續執行下一條命令。
事務中的錯誤處理 語法錯誤或系統錯誤:對於這種類型的錯誤,在client執行事務前就能發現(事務中命令成功提交會返回queued),多數client會選擇discard事務。從Redis2.6.5開始,服務端會記錄這樣的錯誤,在用戶端exec時報錯並自動丟棄該事務; 執行時報錯:服務端會忽略該條語句的錯誤,直接執行事務中的下一跳語句。也就是說,執行時錯誤沒有復原的操作,官方的說法是這樣有利於保持Redis簡單高效。
Jedis代碼示範
// multi實現事務private void doWithMulti(Jedis jedis) { Transaction transaction = jedis.multi(); transaction.incr("num.trans"); transaction.set("val.trans", "inTrans"); transaction.sismember("wilson.friends", "tom"); System.out.println("Transaction result:"+transaction.exec()); jedis.del(new String[]{"num.trans","val.trans"});}// 樂觀鎖實現原子操作private void doWithMultiAndCAS(Jedis jedis) { List<Object> res = null; do { jedis.watch("wilson.friends"); Boolean isFriend=jedis.sismember("wilson.friends", "katty"); if (!isFriend) { Transaction transaction = jedis.multi(); // 各種商務邏輯 transaction.incr("num.trans"); transaction.set("val.trans", "inTrans"); res = transaction.exec(); System.out.println("Transaction result:"+res); } } while (null == res);}// pipeline+multi實現事務private void doWithPipeline(Jedis jedis) { Pipeline line = jedis.pipelined(); line.multi(); line.incr("num.trans"); line.set("val.trans", "inTrans"); line.sadd("wilson.friends", "gary"); Response<String> numRes = line.get("num.trans"); line.exec(); line.sync(); System.out.println("num.trans val:"+numRes.get());}