以前一直了解redis中的事務機制,知道事務並無真正的回滾,只是會中斷,中斷後的將不會執行,中斷前的會生效。java
使用是若是遇到但願保持原子性的更改,除了自增的簡單操做,redis作的並非很完善。redis
在項目中遇到了一個使用redis並但願原子性更改值的須要,記錄一下。code
/** * @Description: value greater than get value then set value 設置key值,若是傳的value比redis中的value大則設置傳入的value * @param key 須要設置的key * @param value 須要設置的value * @return: boolean * @Author: wangtongxing * @Date: 2019/1/11 */ public static boolean vGtGetSet(String key, long value) { String s = null; Jedis jedis = null; try { jedis = JedisPoolUtils.getJedis(); List<Object> exec = null; int i=0; while ((exec == null || exec.size()==0 || !"OK".equals(exec.get(0))) && i<5){ jedis.watch(key); String getS = jedis.get(key); long get = 0; if (StringUtils.isNotEmpty(getS)){ try { get = Long.parseLong(getS); }catch (Exception e){ e.printStackTrace(); } } if (value>get){ Transaction transaction = jedis.multi();//返回一個事務控制對象 transaction.set(key, Long.toString(value));//預先在事務對象中裝入要執行的操做 transaction.expire(key, CACHE_6_MONTHS); exec = transaction.exec();//執行 }else { jedis.unwatch(); return true; } i++; } } catch (Exception e) { e.printStackTrace(); } finally { JedisPoolUtils.returnRes(jedis); } return false; }
使用中須要注意的幾個點:對象
1.在不成功的狀況下,通常須要重試幾回,在重試的過程當中每次循環都須要從新watch操做,由於每次事務提交以後,watch操做都會失效。事務
2.在事務提交以後返回的結果對象分爲幾種狀況ip
事務提交前,watch的key發生改變,返回的List對象並非null,而是一個初始化後的空對象(size==0)get
事務提交前,watch的key沒有改變,事務提交成功,返回的List對象中有一個"OK"的String對象。io