io.lettuce.core.RedisCommandExecutionException: ERR EXEC without MULTI

在使用redisTemplate的事务功能时,代码运行抛出异常:

java 复制代码
io.lettuce.core.RedisCommandExecutionException: ERR EXEC without MULTI
	at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:147)
	at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:116)
	at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:120)
	at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:111)
	at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:747)
	at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:682)
	at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:599)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:748)

出现上面这个异常的原因是在执行redis事务时,执行exec命令时没有检查到multi命令;这是因为redis需要所有命令都在一个连接上提交才能判断到命令是否执行,而默认使用连接池提交命令时不能保证所有命令都在一个连接上提交。为了解决这个问题,在springboot中需要在方法上面添加@Transactional注解,并且方法内设置开启事务支持,方法代码如下:

java 复制代码
@Transactional
public void runTransaction() {
    // 开启事务支持
    redisTemplate.setEnableTransactionSupport(true);
    // 表示开启事务
    redisTemplate.multi();

    // 执行多个redis命令
    redisTemplate.opsForValue().set("key1", "value1");
    redisTemplate.opsForValue().set("key2", "value2");
    redisTemplate.opsForValue().set("key3", "value3");

    // 提交执行
    redisTemplate.exec();
    // 取消执行
    // redisTemplate.discard();
    // 关闭事务支持
    redisTemplate.setEnableTransactionSupport(false);
}

上面代码还需要注意事务方法不能在同一个类内部调用,@Transactional 注解需要代理才能生效,否则事务还是不生效,上面的异常依然会抛出。

上面这种处理事务方式不太推荐,在redisTemplate中建议使用SessionCallback实现事务功能。

相关推荐
用户0942485680326 分钟前
第19章:库存扣减与秒杀系统:Redis 扛峰值流量
redis·架构·源码
爱写Bug的浮游31 分钟前
RTA高频请求下的Redis短缓存工程闭环
redis
没有气的汽水35 分钟前
redis加了个分片,把线上写挂了一个多小时
redis
aiks_yuan42 分钟前
Spring Boot SSE 流式输出变成一次性返回怎么办:大模型打字机效果失效的 5 个原因(Spring Boot 4.1.2 实测)
spring boot
xixiaoyunya2 小时前
Redis缓存三大问题实战:穿透、击穿、雪崩,我用一个电商秒杀场景讲清楚
数据库·redis·缓存
Thomas.Sir3 小时前
第15课:SpringBoot连接池详解:HikariCP配置、调优、监控,4.x连接池新特性
java·spring boot
鶴哥只手遮天3 小时前
《Redis 8.10.3 深度剖析》系列 · 第 1 章·全景与源码地图:版本谱系、构建体系、全局状态与启动链路
redis·后端·开源
70后写java的老码农3 小时前
docker-compose 部署 Redis Stack Server 6.2.6-v19
redis·docker
VimorphTech4 小时前
每批开 4 个线程,为什么限制不住 TTS 的总并发?
java·spring boot·spring
杨凯凡4 小时前
Spring Boot 缓存一致性怎么保证?@Cacheable、@CacheEvict 与事务提交时机实战
java·spring boot·spring cache·后端开发·缓存一致性