Redis 事务操作

重新配置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 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 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 事务操作)