文章目录
1. redisTemplate
- redisTemplate默认使用的是JDK序列化,但是可以主动设置
- redisTemplate执行两条命令其实是在两个连接里完成的,因为redisTemplate执行完一个命令就会对其关闭,但是redisTemplate额外为什么提供了RedisCallback和SessionCallBack两个接口
2. StringRedisTemplate
- StringRedisTemplate继承RedisTemplate,只是提供字符串的操作,复杂的Java对象还要自行处理
RedisCallback和SessionCallBack:
- 作用: 让RedisTemplate进行回调,通过他们可以在同一条连接中执行多个redis命令
- SessionCalback提供了良好的封装,优先使用它,redisCallback太复杂还是不要使用为好
3. 测试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;
}
});
}
}
}
4 . redis相关的同样适用lambda
@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;
});
}
5.Redis SessionCallback和redis 事务的区别
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
如果被监控的键发生了变化就会取消事务,没有变化九执行事务(注意:即使被赋予了相同的值,同样视为发生变化,不予执行事务)
6. 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保证不会插入其他人语句来实现隔离。(可以预见到此机制如果事务中包裹过多的执行长指令,可能导致长时间阻塞其他人)
标签:SessionCallback,redis,watch,事务,value,res,redisTemplate From: https://www.cnblogs.com/Jonkidi/p/16753946.html