一、問題描述
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命令進行封裝,遠看可以解決問題時,代碼實現:
- stringRedisTemplate.multi();
- stringRedisTemplate.delete("test");
- stringRedisTemplate.opsForValue().set("test","2");
- stringRedisTemplate.exec();
結果保 錯誤:
我們查詢multi、delete等源代碼,發現會執行RedisTemplate類中execute()方法進行跟蹤發現 RedisCallback中doInRedis獲取的RedisConnection每次都是新的,所以才導致該問題。
分析Redis源代碼:
我們查看multi實現


三、解決方案
只能自己實現RedisCallBack底層,采用RedisTemplate的SesionCallback來完成在同一個Connection中,完成多個操作的方法:
- SessionCallback<Object> sessionCallback=new SessionCallback<Object>(){
- @Override
- public Object execute(RedisOperations operations) throws DataAccessException{
- operations.multi();
- operations.delete("test");
- operations.opsForValue.set("test","2");
- Object val=operations.exec();
- return val;
- }
- }
- StringRedisTemplate.execute(sessionCallback);