事务
Ø MULTI,EXEC操作:事务的开始和结束标记
n 执行Multi命令,redis反馈ok表示开始事务;执行EXEC命令,结束事务,开始顺序执行事务中的操作。
127.0.0.1:6379[5]> MULTIOK127.0.0.1:6379[5]> set k1 1QUEUED127.0.0.1:6379[5]> set k2 2QUEUED127.0.0.1:6379[5]> exec1) OK2) OK127.0.0.1:6379[5]> get k1"1"127.0.0.1:6379[5]> get k2"2"
错误处理
语法错误:执行命令不存在或参数不对,都是语法错误,只有事务中有一处错误,redis执行exec命令后,会直接返回错误,正确的命令也不会被执行。
127.0.0.1:6379[5]> multiOK127.0.0.1:6379[5]> set name zhangsanQUEUED127.0.0.1:6379[5]> sss age 10(error) ERR unknown command 'sss'127.0.0.1:6379[5]> set sex nanQUEUED127.0.0.1:6379[5]> exec(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6379[5]> get name(nil)127.0.0.1:6379[5]> get sex(nil)
运行错误:此类错误执行命令没错,但是操作对应的键有误,会造成运行时才会发现的错误,但是不影响其它正确命令的执行。
127.0.0.1:6379[5]> multiOK127.0.0.1:6379[5]> set k 10QUEUED127.0.0.1:6379[5]>sadd k 20//使用散列集合的命令操作strings类型数据QUEUED127.0.0.1:6379[5]> set k 100QUEUED127.0.0.1:6379[5]> exec1) OK2) (error) WRONGTYPE Operation against a key holding the wrong kind of value3) OK127.0.0.1:6379[5]> get k"100"
WATCH命令
监控指定键,若被监控的键在以下事务执行前被修改,则包含对此键有操作动作的事务不执行,返回nil。
通俗的来讲就是。当你一旦开始watch一个key的时候,开启了一个事务,那么在这个事务提交之前数据发生改变,那么就事务执行失败。从下面的例子就可以看出。
127.0.0.1:6379[5]> get k"20"127.0.0.1:6379[5]> set k 30OK127.0.0.1:6379[5]>watch kOK127.0.0.1:6379[5]> set k 40OK127.0.0.1:6379[5]> multiOK127.0.0.1:6379[5]> set k 50QUEUED127.0.0.1:6379[5]> exec(nil)127.0.0.1:6379[5]> get k"40"
java中redis的watch与Transaction功能使用
https://www.liangzl.com/get-article-detail-38409.html
非常好的一个文章。
需求:在项目中遇到了一个使用redis并希望原子性更改值的需要,记录一下。
设置key值,如果传的value比redis中的value大则设置传入的value
/*** @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.在事务提交之后返回的结果对象分为几种情况
事务提交前,watch的key发生改变,返回的List对象并不是null,而是一个初始化后的空对象(size==0)
事务提交前,watch的key没有改变,事务提交成功,返回的List对象中有一个”OK”的String对象。
