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实现事务功能。

相关推荐
upanddown1 小时前
redis实战——秒杀篇之redisson实现分布式锁
redis
趁你还年轻_2 小时前
Redis大量key集中过期怎么办
数据库·redis·缓存
神仙别闹2 小时前
基于Java(SpringBoot、Mybatis、SpringMvc)+MySQL实现(Web)小二结账系统
java·spring boot·mybatis
全职计算机毕业设计3 小时前
SpringBoot+Mysql实现的停车场收费小程序系统+文档
spring boot·mysql·小程序
努力的小郑3 小时前
BeanFactory与ApplicationContext全面指南与实战
spring boot·spring
crud3 小时前
Spring Boot 整合 MyBatis-Plus:从入门到精通,一文搞定高效持久层开发!
java·spring boot·mybatis
alien爱吃蛋挞5 小时前
【JavaEE】Spring Boot项目创建
spring boot·java-ee
wxid:yiwoxuan6 小时前
购物商城网站 Java+Vue.js+SpringBoot,包括商家管理、商品分类管理、商品管理、在线客服管理、购物订单模块
java·vue.js·spring boot·课程设计
要阿尔卑斯吗7 小时前
对一个变化的 Set 使用 SSCAN,元素被扫描的情况:
redis
Java知识库7 小时前
「深度拆解」Spring Boot如何用DeepSeek重构MCP通信层?从线程模型到分布式推理的架构进化
java·开发语言·spring boot·程序员·编程