redis使用watch乐观锁+事务保证操作唯一
默认不支持事务,不用SessionCallback直接写会报错No ongoing transaction. Did you forget to call multi?,需要单独开启redisTemplate.setEnableTransactionSupport(true); 使用SessionCallback保证在同一个连接里,因为redis每一个指令都是一个新连接,这种方式更好
public Boolean setTransaction(String key, QrCodeInfo qrCodeInfo) {
// 使用sessionCallBack处理
SessionCallback sessionCallback = new SessionCallback() {
@Override
public List execute(RedisOperations operations) throws DataAccessException {
operations.watch(key);
if(qrCodeInfo.getStstus().equals(QrCodeStatusEnum.UNSCAN.getCode())) {
qrCodeInfo.setStstus(QrCodeStatusEnum.CONFIRMING.getCode());
operations.multi();
operations.opsForValue().set(key, JSON.toJSONString(qrCodeInfo), 0);
operations.opsForValue().get(key);
try{
List exec = operations.exec();
return exec;
} catch (Exception e){
log.info("exec", e);
}
}
return null;
}
};
//提交事务
List execute = (List) redisTemplate.execute(sessionCallback);
if(execute==null || execute.size()==0){
return false;
}else {
return true;
}
}
-
遇到的坑
List exec = operations.exec();不论成功提交事务还是失败返回的都是空list,最后加了一句get命令到事务里,成功提交事务返回的就是get的结果,才判断事务是否成功提交 -
多次set不改变有效期
redis第二次set是会先删除数据的,多以为了保证第一次设置的有效期不失效,且不用每次都设置有效期,可以使用偏移量operations.opsForValue().set(key, JSON.toJSONString(qrCodeInfo), 0); connection.setRange(rawKey, rawValue, offset);
0表示不偏移,注意,这种情况 修改的值,长度不能比原值长度小。setRange ,在范围内替换,从索引1位置开始去一个个替换,所以当第二次修改的值长度小的时候,不能完全替换原值的所有位置字符。导致出现问题。



