Redis RedisCommandExecutionException: ERR DISCARD without MULTI

redis 操作事务报错

报错信息
Caused by: io.lettuce.core.RedisCommandExecutionException: ERR DISCARD without MULTI

原因 :

因为redisTemplate使用事务命令multi之后discard命令和exec命令二选一,因为不管执行哪一个代码最后都会关闭当前的连接,看源码


public static void unbindConnection(RedisConnectionFactory factory) {

		RedisConnectionHolder conHolder = (RedisConnectionHolder) TransactionSynchronizationManager.getResource(factory);

		if (conHolder == null) {
			return;
		}

		if (log.isDebugEnabled()) {
			log.debug("Unbinding Redis Connection");
		}

		if (conHolder.isTransactionActive()) {
			if (log.isDebugEnabled()) {
				log.debug("Redis Connection will be closed when outer transaction finished");
			}
		} else {

			RedisConnection connection = conHolder.getConnection();
			conHolder.released();

			if (!conHolder.isOpen()) {

				TransactionSynchronizationManager.unbindResourceIfPossible(factory);

				doCloseConnection(connection);   //关闭连接
			}
		}
	}

事务回滚案例

redis配置:以下使用事务需要注意两点第一点是开启支持事务,以及事务的执行建议使用redisTemplate的execute方法实现接口,因为官网建议的spring官网https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#tx.spring


/**
     * 序列化相关的配置
     */
    @Bean("myRedisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory  factory) {
        RedisTemplate<String, Object> redisTemplate  = new RedisTemplate<>();
        //支持事务
        redisTemplate.setEnableTransactionSupport(true);

        //json方式序列化
        Jackson2JsonRedisSerializer jackson = new Jackson2JsonRedisSerializer<>(Object.class);
        redisTemplate.setConnectionFactory(factory);
        //String方式序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        //配置序列化的方式不用设置
        /*redisTemplate.setDefaultSerializer();
        redisTemplate.setStringSerializer();
        redisTemplate.setEnableDefaultSerializer();*/

        //设置所有的key为string方式序列化
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        //设置所有的value为jackson方式序列化
        redisTemplate.setValueSerializer(jackson);
        redisTemplate.setHashValueSerializer(jackson);

        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

无效事务案例 :

在jedis,以下是可以回滚的

 redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
                List<Object> exec = null;
                try {
                    operations.multi();

                    operations.opsForValue().set((K) "username", (V) "wyx");

                    operations.opsForSet().members((K) "username");   //用set类型获取string类型的值,

                    exec = operations.exec();
                } catch (Exception e) {
                    redisTemplate.discard();
                }
                return exec;
            }
        });
    }

有效事务案例 :

 redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
                List<Object> exec = null;
                try {
                    operations.multi();

                    operations.opsForValue().set((K) "username", (V) "wyx");

                    operations.opsForSet().members((K) "username");   //用set类型获取string类型的值,
                    System.out.println(1/0);  //redis命令使用的错误将不会回滚
                    exec = operations.exec();
                } catch (Exception e) {
                    redisTemplate.discard();  
                }
                return exec;
            }
        });
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值