redis事务及锁的应用

 

一、redis支持简单的事务(不支持回滚)

redis提供的事务是将多个命令打包,然后一次性、按照先进先出的顺序(FIFO)有序的执行。在执行过程中不会被打断(在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中),当事务队列中的所以命令都被执行(无论成功还是失败)完毕之后,事务才会结束。

MULTI       //开始事务

SET   ...   //命令1入队

GET   ...   //命令1入队

SADD  ...   //命令1入队

......

EXEC        //执行事务(一次执行1.2.3...)

如上所述,Redis的事务以特殊命令MULTI开始,之后跟着用户传入的多个命令,最后以EXEC未结束。由于这种简单的事务在EXEC命令被调用之前不会执行任何实际操作,所以用户将没有办法根据根据读到的数据来做决定。

 

二、redis与mysql的区别

 

Mysql

Redis

开启

Start transtration

multi

语句

普通sql

普通命令

失败

Rollback回滚

Discard取消

成功

Commit

Exec

注:

rollback与discard的区别

如果已经成功执行了两条语句,第三条语句出错

Rollback后前两条语句影响消失

Discard只是结束本次事务,前两条语句照成的影响仍然还在

 

注:

在mulit后面的语句中,语句出错肯能有两种情况

1)语法就有问题

这种exec时报错,所有语句得不到执行

2)语法本身没错,但适用对象有问题,比如zadd操作link对象,exec之后回执行正确的语句,并跳过不适当的语句

(如果zadd操作link这种事怎么避免?这一点由程序员解决)

 

Eg:

正常执行

127.0.0.1:6379> set wang 200
OK
127.0.0.1:6379> set zhao 700
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby zhao 100
QUEUED
127.0.0.1:6379> incrby wang 100
QUEUED
127.0.0.1:6379> get zhao
QUEUED
127.0.0.1:6379> exec
1) (integer) 600
2) (integer) 300
3) "600"

 

错误执行1:语法错误

127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby zhao 100
QUEUED
127.0.0.1:6379> sda
(error) ERR unknown command `sda`, with args beginning with:
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> mget zhao wang
1) "600"
2) "300"

错误执行2:执行对象不对

127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby zhao 100
QUEUED
127.0.0.1:6379> sadd wang pig
QUEUED
127.0.0.1:6379> exec
1) (integer) 500
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> mget zhao wang
1) "500"
2) "300"

 

思考:

我正在买票

Ticket-1,money-100

而票只有一张,如果在multi之后和exec之前,票被别人买走了,即ticket变成0了,

我该如何观察这种情况,并不在提交

 

悲观想法

世界充满危险。肯定有人和我抢,只有我能操作[悲观锁]

 

乐观想法

没有那么多人和我抢,因此我只需要注意,有没有人更改了ticket的值就可以了[乐观的]

 

Redis的事务中,启用的是乐观锁,只负责监控key没有被改动

具体的指令----- watch命令

127.0.0.1:6379> set ticket 1
OK
127.0.0.1:6379> set lisi 300
OK
127.0.0.1:6379> set wang 300
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decr ticket
QUEUED
127.0.0.1:6379> decrby lisi 100
QUEUED
执行exec之前 另外一个线程操作了减票操作
127.0.0.1:6379> decr ticket
(integer) 0
这时再执行exec,就会出现票为-1
127.0.0.1:6379> exec
1) (integer) -1
2) (integer) 200

Watch命令

127.0.0.1:6379> set ticket 1
OK
127.0.0.1:6379> watch ticket
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decr ticket
QUEUED
127.0.0.1:6379> decrby lisi 100
QUEUED
执行exec之前 另外一个线程操作了减票操作
127.0.0.1:6379> decr ticket
(integer) 0

这时再执行exec,就会出现执行不成功

127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> mget ticket lisi
1) "0"
2) "200"
unwatch取消监视
127.0.0.1:6379> UNWATCH
OK