redis 是线程安全的
ConurrentHashMap
线程不安全原理一致redis 主从复制的集群是 AP 的
分布式锁思路梳理
String bizLockKey = "RLK:" + biz_prefix + biz_id
so:wms:
这是一个销售单流转到 wms 系统的前缀bizLockKey
String bizLockValue = ip_short + UUID + thread
setnx
获取分布式锁,需要携带值、超时时间redisTemplate.opsForValue.setIfAbsent(bizLockKey,bizLockValue,time,timeUnit);
Jedis jedis = RedisUtils.getJedis();
String lua = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
"then\n" +
" return redis.call(\"del\",KEYS[1])\n" +
"else\n" +
" return 0\n" +
"end";
try{
if("1".equals(jedis.eval(lua, Arrays.asList(key),Arrays.asList(vlue)))){
// do sth
}
}finally {
if(null != jedis) jedis.close();
}
bizLockKey
携带随机信息(保证不会误删除)while(true){
redis.watch(key);
if(Value.equals(redis.opsForValue().get(key))){
redis.setEnableTransactionSupport(true);
redis.multi();
if(!CollectionUtils.isEmpty(redis.delete(Key))){
redis.unwatch();
break;
}
}
}
RLock lock = redisson.getLock(key,value);
try {
lock.lock();
// ...
}finally {
if(lock.isLocked() && lock.isHeldByCurrentThread())
lock.unlock();
}
分布式锁坑总结
setnx
,实际是 set key value nx px 毫秒数
上锁,使上锁和超时设置原子化特性
exec
之前事务中的指令都未被执行, exec
之后各个指令都不会被打断流程
redis 事务由下面流程组成
MULTI
EXEC
DISCARD
WATCH
/ UNWATCH
WATCH key1 key2
事务示例
# 组织指令并执行
multi
set k1 v1
set k2 v2
exec
# 组织指令并撤销
multi
set k1 v1
set k2 v2
set k3 v3
discard
事务中的指令错误
指令错误分为 MULTI
阶段错误 和 EXEC
阶段错误
MULTI
阶段错误,导致整个 MULTI
无法执行(不能 exec
)EXEC
阶段错误,只导致出错误的指令执行失败指令错误示例
multi
set k1 v1
set k2
# 下面的指令会拒绝执行,因为 multi 中 set k2 指令错误
exec
multi
set k1 v1
incr k1
set k2 v2
# exec 成功执行,上面命令中只有第二条执行失败,因为 k1 的值 v1 无法自增
exec
事务冲突
成因说明
if(condition) then...
逻辑解决方式
redis 提供了 基于乐观锁 的监视指令 watch
,使用流程如下
WATCH key...
UNWATCH key...