RedisTemplate实现事物问题剖析和解决

一、问题描述

     Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,Redis对事物支持不会很复杂,当一个客服端连接Redis服务时,发出了MULTI命令时,这个连接会进入事物,在执行MULTI命令之后,执行所有的命令都不会执行,会先放到一个队列中,会提示正在Query,当最后执行EXEC命令之后,Redis会按照之前的进入队列的顺序,执行命令。

      Spring Data Redis 是对JRedis的客服端进行很好的封装, spring Data Redis的RedisTemplate提供了MULTI、EXEC命令进行封装,但RedisTemplate先执行调用MULTI方法,然后在执行其它的命令,最后执行EXEC方法时,会出现报错:Caused by:Redis.clents.jedis.exceptions.JedisDataException:ERR EXEC without MULTI问题。

二、原因分析

     Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,我们需要重新添加数据,对原先的数据进行删除,在多个线程情况下数据会丢失,所以我们需要事务完成相应的效果。

      Spring Data Redis的RedisTemplate提供了MULTI、EXEC命令进行封装,远看可以解决问题时,代码实现:

     

[java] view plain copy
 
  1. stringRedisTemplate.multi();  
  2. stringRedisTemplate.delete("test");  
  3. stringRedisTemplate.opsForValue().set("test","2");  
  4. stringRedisTemplate.exec();  

       结果保 错误:

         

       

            我们查询multi、delete等源代码,发现会执行RedisTemplate类中execute()方法进行跟踪发现 RedisCallback中doInRedis获取的RedisConnection每次都是新的,所以才导致该问题。

        分析Redis源代码:

               我们查看multi实现

                 
                                
                    跟踪发现RedisConnection conn每次都是新的,导致出现那个错误

三、解决方案

       只能自己实现RedisCallBack底层,采用RedisTemplate的SesionCallback来完成在同一个Connection中,完成多个操作的方法:

  1. SessionCallback<Object>   sessionCallback=new SessionCallback<Object>(){  
  2.   @Override  
  3.    public Object execute(RedisOperations operations) throws DataAccessException{  
  4. operations.multi();  
  5. operations.delete("test");  
  6. operations.opsForValue.set("test","2");  
  7. Object val=operations.exec();  
  8. return val;  
  9. }  
  10. }  
  11. StringRedisTemplate.execute(sessionCallback); 
原文地址:https://www.cnblogs.com/zxf330301/p/6889202.html