TENCHIANG / blog

issue blog
10 stars 1 forks source link

Redis事务 #44

Open TENCHIANG opened 5 years ago

TENCHIANG commented 5 years ago

事务Trasaction的4个性质(ACID)

Redis事务中的错误和回滚

redis事务运行过程中可能会碰到3种错误,严重错误是可以回滚的,轻微错误和客观条件的错误不会回滚

入队错误

redis事务中每添加一条命令就相当于在事务队列里入队,如果在这个过程中有一些语法错误或者其它严重错误,那么redis会记录这种错误(>=2.6.5),并且在执行EXEC的时候,报错回滚事务中所有的命令,并且终止事务(注意这3个动词,对于redis事务来说这是3个独立不同的动作)。像输入了错误的命令或参数、内存不足(maxmemory)等都会引发入队错误。 入队错误报错例子:(error) EXECABORT Transaction discarded because of previous errors.

执行错误

执行错误一般是一些不太严重的错误,如你lpop了一个字符串类型的key(处理了错误类型的键)。 redis碰到执行错误,不会终止事务也不会回滚,而是保证事务其他部分的正常运行,会返回其它部分的执行情况(如OK),也会报错。 执行错误报错例子:(error) WRONGTYPE Operation against a key holding the wrong kind of value

进程终结

服务端直接终结,属于客观条件的错误,虽然很严重,但是redis已经处理不了了,又因为redis事务没有持久化,所以不能回滚,无法保证一致性

Redis事务流程

redis事务是通过MULTIEXECDISCARDWATCHUNWATCH五条命令实现的

  1. 可以先WATCH一些键,避免事务执行之前该键被其它命令改动(乐观锁)
  2. 开启一个事务,用MULTI,总是返回OK
  3. 命令入队,命令不会立刻执行,而是需要EXEC执行
  4. EXEC执行事务,用DISCARD清空事务队列,并取消事务
  5. 事务结束后,不论成功或失败,自动UNWATCH所有key

WATCH与乐观锁

WATCH命令可以为redis事务提供check-and-set (CAS)行为,被称为“乐观锁”。 WATCH命令可以监视一个(或多个) key ,如果在事务EXEC之前这些key被其他命令所改动,那么整个事务将被abort,当事务被打断,exec就会返回空值nil。 这里被key被其它命令改动又分两种情况(当然都是exec之前):

  1. watch之后,multi之前,被本身set
  2. watch之后,multi之后,exec之前,被别的客户端set

这两种情况都会触发乐观锁,如果触发了乐观锁而导致事务打断,可以不断重试(也需要重新watch,但是watch又不能作为事务本身命令的一部分(error) ERR WATCH inside MULTI is not allowed),直到事务执行成功(说明此时另外的客户端已经没有在set键了)。

redis事务示范

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key1 1
QUEUED
127.0.0.1:6379> HSET key2 field1 1
QUEUED
127.0.0.1:6379> SADD key3 1
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (integer) 1
3) (integer) 1

问题:watch和setnx的异同(分布式锁)

watch的意思是CAS(check-and-set),检查没有被改变则改变之,改变则exec报错 setnx的意思是NX(not-exist-and-set),不存在则set之返回1(成功set一个key<只支持一个key的set>),存在则返回0 当然还存在XX(exist-and-set),意思是存在则set。watch不是属于 XX ,因为可以watch一个不存在的key,如果事务exec前存在了,则报错(保证key是在事务中create的)

参考

redis事务