赞
踩
RedisCallback和SessionCallBack:
@Api("redis") @Controller @RequestMapping("/redis/*") public class RedisTestController { @Autowired private RedisTemplate redisTemplate; @ApiOperation(value = "testSessionCallback", notes = "testSessionCallback") @RequestMapping(value = "/testSessionCallback", method = RequestMethod.GET) @ResponseBody public void testSessionCallback( @RequestParam("key") String value) { testSessionCallback(redisTemplate, value); } public void testSessionCallback(RedisTemplate redisTemplate, String value) { redisTemplate.execute(new SessionCallback() { @Override public Object execute(RedisOperations redisOperations) throws DataAccessException { redisOperations.opsForValue().set("wanwan", value); String myValue = String.valueOf(redisOperations.opsForValue().get("wanwan")); System.out.println(myValue); return myValue; } }); } } }
@ApiOperation(value = "testSessionCallbackLambda", notes = "testSessionCallbackLambda") @RequestMapping(value = "/testSessionCallbackLambda", method = RequestMethod.GET) @ResponseBody public void testSessionCallbackLambda( @RequestParam("key") String value) { testSessionCallbackLambda(redisTemplate, value); } public void testSessionCallbackLambda(RedisTemplate redisTemplate, String value) { redisTemplate.execute((RedisOperations redisOperations) -> { redisOperations.opsForValue().set("wanwan", value); String myValue = String.valueOf(redisOperations.opsForValue().get("wanwan")); System.out.println(myValue); return myValue; }); }
redis事务时基于SessionCallback实现的,因为要在一个连接里执行命令,那我们看看具体的实现,如下:
@ApiOperation(value = "multi测试接口", notes = "redis事务测试接口") @RequestMapping(value = "/multi", method = RequestMethod.GET) @ResponseBody public Map<String, Object> testmulti() { redisManager.setStr("wanwan", "wd小兔兔"); List list = (List) redisTemplate.execute((RedisOperations res) -> { //设置监控key,在exec执行前如果这个key对应的值,发生了变化,事务bu执行 //通常监控的key可以是ID,也可以是一个对象 res.watch("wanwan"); // 其实watch可以注释掉,或者设置成不监控 res.unwatch(); //开启事务,在exec执行前 res.multi(); res.opsForValue().increment("wanwan", 1); res.opsForValue().set("wanwan2", "我的小兔兔1"); Object value2 = res.opsForValue().get("wanwan2"); System.out.println("命令在队列,所以取值为空" + value2 + "----"); res.opsForValue().set("wanwan3", "我的小兔兔3"); Object value3 = res.opsForValue().get("wanwan3"); System.out.println("命令在队列,所以取值为空" + value3 + "----"); return res.exec(); }); System.out.println(list); Map<String, Object> map = new HashMap<>(); map.put("success", true); System.out.println(";;;" + map.toString()); return map; }
发现其实事务就是基于SessionCallback实现了一个watch
如果被监控的键发生了变化就会取消事务,没有变化九执行事务(注意:即使被赋予了相同的值,同样视为发生变化,不予执行事务)
可能你会对redis事务的watch有一个疑问?就是watch
了几次?如果redis事务中要执行100条命令,那么watch会watch几次?
其实我的理解是:
在执行前一直在watch,但是执行过程中比如开始执行100条命令中的第一条后,
就不会watch了,因为redis时单线程的,你在执行过程中,别的命令根本无法执行
那你会说:如果这个事务要执行10分钟,我这这10分钟内通过手动更改一个键的值可以不,答案是不行
因为redis单线程,
redis的事务类似mysql的串行化隔离界别,执行期间不会乱入其他语句。redis在事务使用乐观锁。redis使用的是乐观锁方式,这种方式允许exec前修改,这时会触发异常通知。
redis通过watch来监测数据,在执行exec前,监测的数据被其他人更改会抛出错误,取消执行。而exec执行时,redis保证不会插入其他人语句来实现隔离。(可以预见到此机制如果事务中包裹过多的执行长指令,可能导致长时间阻塞其他人)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。