Redis配置了redisTemplate.setEnableTransactionSupport(true)之后的坑,以及自己的理解

本文整合的redis客户端是lettucce,话不多说上代码。

先配置一个RedisTemplete的实例,在里面指定redis支持数据库的事务

@Bean
public RedisTemplate redisTemplate(LettuceConnectionFactory factory){
    RedisTemplate redisTemplate = new RedisTemplate();
    //使用LettuceConnectionFactory 代替 RedisConnectionFactory
    redisTemplate.setConnectionFactory(factory);
    //配置序列化方式
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    redisTemplate.setHashKeySerializer(new StringRedisSerializer());
    redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

    //设置redis支持数据库的事务
    redisTemplate.setEnableTransactionSupport(true);

    return redisTemplate;
}

写个简单demo测试下事务是否有效

@Transactional(rollbackFor = Exception.class)
public void changeCount2(String name) throws Exception{
    redisTemplate.opsForValue().set(name,123);
    dotest();
    redisTemplate.opsForValue().set(name,345);
}
public void dotest() throws Exception{
    rabbitBackUpDao.insert(RabbitBackUp.builder()
            .exchange("asdf")
            .routingKey("fdsa")
            .correlationDataId("1234123ads")
            .data("qwerty")
            .build());
    throw new Exception();
}

亲测redis存进去的值随着mysql的事务回滚掉了,你不是说有问题吗?问题在哪呢?下面我就列出几种情况

写个乐观锁的demo

@Transactional(rollbackFor = Exception.class)
public void changeCount2(String name) throws Exception{
    redisTemplate.watch(name);
    Integer number = (Integer)redisTemplate.opsForValue().get(name);
    number ++;
    redisTemplate.multi();
    redisTemplate.opsForValue().set(name,number);
    redisTemplate.exec();
    dotest();
    redisTemplate.opsForValue().set(name,345);
}

报错

看下源码

它说事务已经开启了,再watch是不被允许的。

你不让我乐观锁了,那我就去掉,看看还会有啥问题

@Transactional(rollbackFor = Exception.class)
public void changeCount2(String name) throws Exception{
    //redisTemplate.watch(name);
    Integer number = (Integer)redisTemplate.opsForValue().get(name);
    number ++;
    redisTemplate.multi();
    redisTemplate.opsForValue().set(name,number);
    redisTemplate.exec();
    dotest();
    redisTemplate.opsForValue().set(name,345);
}

结果是number是个空,为什么会是空呢?再看代码

结果加入到了一个队列中,然后返了null

为什么会出现这两种情况?

其实redis的事务本身就是一组命令集合,multi用来标记事务开始,exec用来执行之间的命令,由于贴有@Transactional标签加上templete的事务设置,框架会自动去帮我们开启和执行事务,所以,一开始isMulti就是ture,当我们get的时候,此时并不会立即执行这条命令,而是等框架给我们exec的时候去真正执行返回结果,那么立即返回了个null,所以使用了@Transactional和redisTemplate.setEnableTransactionSupport(true)在本方法中不能使用get去取值或者去watch,也不要去mutli和exec了,正常执行set就行了。

 

 

 

 

 
  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值