事务和分布式锁
事务:一组命令集合
主要命令multi 和exec
multi set a 1 sadd s1 a ...... exec
错误处理
- (1)语法错误
127.0.0.1:6379> multi OK 127.0.0.1:6379> set a 1 QUEUED 127.0.0.1:6379> set b (error) ERR wrong number of arguments for 'set' command 127.0.0.1:6379> seta c (error) ERR unknown command 'seta' 127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> get a (nil) 127.0.0.1:6379>
只要有任何一个语法错误,正确的也不会执行
- (2)运行错误
比如a是string类型,然后按照hash操作 hset a k1 v1
127.0.0.1:6379> keys * (empty list or set) 127.0.0.1:6379> set a 1 OK 127.0.0.1:6379> type a string 127.0.0.1:6379> multi OK 127.0.0.1:6379> set n 1 QUEUED 127.0.0.1:6379> hset a k1 v1 QUEUED 127.0.0.1:6379> set m 2 QUEUED 127.0.0.1:6379> exec 1) OK 2) (error) WRONGTYPE Operation against a key holding the wrong kind of value 3) OK 127.0.0.1:6379> mget n m 1) "1" 2) "2" 127.0.0.1:6379> type a string
正确的指令是被执行了,redis事务不支持回滚,所以需要开发者自己处理
开发中规范键名,一般不会出现这种问题
DISCARD取消事务
分布式锁
setnx a:lock 1 expire a:lock 5 del a:lock
为了使setnx和expire能一起执行,而expire的执行又依赖setnx是否成功,显然放事务里是不成立的
setnx和expire组合在一起的原子指令
set a:lock 1 ex 10 nx
以上是这只a:lock 为1 有效期为10s的原子操作
超时问题
Redis 的分布式锁不能解决超时问题,如果在加锁和释放锁之间的逻辑执行的太长,以至于超出了锁的超时限制,就会出现问题。因为这时候第一个线程持有的锁过期了,临界区的逻辑还没有执行完,这个时候第二个线程就提前重新持有了这把锁,导致临界区代码不能得到严格的串行执行。
为了避免这个问题,Redis 分布式锁不要用于较长时间的任务。如果真的偶尔出现了,数据出现的小波错乱可能需要人工介入解决