重新配置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的事务中断、执行失败
网友评论