Redis 事务操作

作者: M_ENG | 来源:发表于2018-04-09 11:34 被阅读37次

    重新配置RedisTemplate 并设置 开启事务

    /**
     * redis 配置类
     *
     * @EnableRedisHttpSession 开启spring session支持
     *
     * 过期时间:maxInactiveIntervalInSeconds 秒
     *
     * @author MENG
     * @version 2017/12/24
     * @see
     */
    @Configuration
    public class RedisConfig extends CachingConfigurerSupport
    {
        /**
         *
         * spring提供两个类操作Redis RedisTemplate(操作对象) StringRedisTemplate(操作String)
         *
         * @param factory
         * @return
         */
        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory)
        {
            RedisTemplate template = new StringRedisTemplate(factory);
    
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    
            ObjectMapper om = new ObjectMapper();
    
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    
            jackson2JsonRedisSerializer.setObjectMapper(om);
    
            template.setValueSerializer(jackson2JsonRedisSerializer);
    
            template.afterPropertiesSet();
    
            //开启事务
            template.setEnableTransactionSupport(true);
    
            return template;
        }
    
    }
    
    

    操作Redis存入数据 使用事务watch multi exec

    /**
         * 数据存入Redis 库
         */
        @Override
        public void writeRedis()
        {
            RedisTemplate redisTemplate = (RedisTemplate)SpringContextUtils.getBean("redisTemplate");
    
            //事务 锁住 key 没有这一步将报错 ERR EXEC without MULTI
            redisTemplate.watch(TableNameConstant.UPLOAD_CONSUME_RECORD);
    
            //事务 2.multi 开始
            redisTemplate.multi();
    
            ListOperations listOperations = redisTemplate.opsForList();
    
            listOperations.rightPush(TableNameConstant.UPLOAD_CONSUME_RECORD,this);
    
            this.setUcrid("meng");
    
            String[] strs = {"a","1"};
    
            int b = Integer.valueOf(strs[Math.random()>=0.5?1:0]);
    
            listOperations.rightPush(TableNameConstant.UPLOAD_CONSUME_RECORD,this);
    
            //事务 2.exec 提交
            redisTemplate.exec();
    
            System.out.println(listOperations.size(TableNameConstant.UPLOAD_CONSUME_RECORD));
    
            List<UploadConsumeRecord> uploadConsumeRecordList = listOperations.range(TableNameConstant.UPLOAD_CONSUME_RECORD,0,-1);
    
            if(uploadConsumeRecordList != null && uploadConsumeRecordList.size() > 0)
            {
                for (UploadConsumeRecord uploadConsumeRecord : uploadConsumeRecordList)
                {
                    System.out.println(uploadConsumeRecord.getUcrid()+"  当前线程:"+Thread.currentThread().getName());
                }
            }
    
    //        redisTemplate.delete(TableNameConstant.UPLOAD_CONSUME_RECORD);
        }
    

    总结

    根据实验结果 当push过程中出现异常时、数据并不会提交到Redis。

    问题

    使用事务时、多个线程对操作同一个key时遇到的问题:
    只有第一个线程的数据插入进去、第二个线程则插入失败

    解决

    不使用事务。。。感觉是废话

    redis事务性质

    当线程中执行redisTemplate.watch(key)之后、redisTemplate.exec()执行之前、有别的线程修改了当前watch的key的数据时、当前事务执行失败

    意思:线程1执行watch(key)、线程2执行wacth(key) 、线程1执行rightpush(key,value)、线程2知道当前wacth的key数据发生改变、所以线程2的事务中断、执行失败

    相关文章

      网友评论

        本文标题:Redis 事务操作

        本文链接:https://www.haomeiwen.com/subject/wswbhftx.html