redis事务原理
redis事务时基于SessionCallback实现的,因为要在一个连接里执行命令,那我们看看具体的实现,如下:
redisTemplate.execute((RedisOperations res) ->{})对SessionCallback实现的是lambda表达式
@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事务和MySQL事务的区别
可能你会对redis事务的watch有一个疑问?就是watch了几次?如果redis事务中要执行100条命令,那么watch会watch几次?
其实我的理解是:
在执行前一直在watch,但是执行过程中比如开始执行100条命令中的第一条后,
就不会watch了,因为redis时单线程的,你在执行过程中,别的命令根本无法执行
那你会说:如果这个事务要执行10分钟,我这这10分钟内通过手动更改一个键的值可以不,答案是不行
因为redis单线程,
redis的事务类似mysql的串行化隔离界别,执行期间不会乱入其他语句。redis在事务使用乐观锁。redis使用的是乐观锁方式,这种方式允许exec前修改,这时会触发异常通知。
redis通过watch来监测数据,在执行exec前,监测的数据被其他人更改会抛出错误,取消执行。而exec执行时,redis保证不会插入其他人语句来实现隔离。(可以预见到此机制如果事务中包裹过多的执行长指令,可能导致长时间阻塞其他人)