Redis+@Transactional巨坑!!!

60 阅读2分钟

Redis不开启事务,不加@Transactional事务注解

@GetMapping(value = "/testRedis", produces = "application/json;charset=UTF-8")
public void testRedis() {
    redisTemplate.opsForValue().set("count","1");
    System.out.println(redisTemplate.opsForValue().increment("count", 1 ));
 }
输出结果: 2

Redis不开启事务,加@Transactional事务注解

@GetMapping(value = "/testRedis", produces = "application/json;charset=UTF-8")
@Transactional
public void testRedis() {
    redisTemplate.opsForValue().set("count","1");
    System.out.println(redisTemplate.opsForValue().increment("count", 1 ));
}
输出结果: 2

Redis开启事务,不加@Transactional事务注解

 @GetMapping(value = "/testRedis", produces = "application/json;charset=UTF-8")
 public void testRedis() {
    redisTemplate.setEnableTransactionSupport(true); //默认false
    redisTemplate.opsForValue().set("count","1");
    System.out.println(redisTemplate.opsForValue().increment("count", 1 ));
 }
 输出结果: 2 正常

开启Redis事务加@Transactional事务注解,在执行redis命令


开启 Redis 事务支持 + @Transactional 注解后,最后其实是标记了一个 Redis 事务块,后续的操作命令是
在这个事务块中执行的。

 //一个进程内
 @GetMapping(value = "/testRedis", produces = "application/json;charset=UTF-8")
 @Transactional
 public void testRedis() {
     redisTemplate.setEnableTransactionSupport(true); //默认false
     redisTemplate.multi();
     redisTemplate.opsForValue().set("count","1");
     System.out.println(redisTemplate.opsForValue().increment("count", 1 ));
     redisTemplate.exec();
     System.out.println(redisTemplate.opsForValue().increment("count", 1 ));
 }
 输出结果:null 3

 //不同进程内
 @GetMapping(value = "/testRedis", produces = "application/json;charset=UTF-8")
 @Transactional
 public void testRedis() {
     redisTemplate.setEnableTransactionSupport(true); //默认false
     redisTemplate.multi();
     redisTemplate.opsForValue().set("count","1");
     System.out.println(redisTemplate.opsForValue().increment("count", 1 ));
     redisTemplate.exec();
 }

 @GetMapping(value = "/testRedis1", produces = "application/json;charset=UTF-8")
 public void testRedis1() {

 System.out.println(redisTemplate.opsForValue().increment("count", 1 ));
 }
 输出结果: 2 正常
 @GetMapping(value = "/testRedis2", produces = "application/json;charset=UTF-8")
 @Transactional
 public void testRedis2() {
     System.out.println(redisTemplate.opsForValue().increment("count", 1 ));
 }
 输出结果:null 实际值已经增加

结论

开启 Redis 事务支持 + @Transactional 注解后,最后其实是标记了一个 Redis 事务块,后续的操作命令是在这个事务块中执行的。 increment递增命令并不会返回递增后的结果,而是返回 null。 同一个进程内 不在一个redis事务内执行返回正常,不同进程内返回异常

异常解决方案如下:

方案一:每次 Redis 的事务操作完成后,关闭 Redis 事务支持,然后再执行 @Transactional 中的 Redis 命
令。
 @GetMapping(value = "/testRedis", produces = "application/json;charset=UTF-8")
 @Transactional
 public void testRedis() {
    redisTemplate.setEnableTransactionSupport(true); //默认false
    redisTemplate.multi();
    redisTemplate.opsForValue().set("count","1");
    System.out.println(redisTemplate.opsForValue().increment("count", 1 ));
    redisTemplate.exec();
    redisTemplate.setEnableTransactionSupport(false);
 }
方案二:创建两个 StringRedisTemplate,一个专门用来执行 Redis 事务,一个用来执行普通的 Redis 命令。