Redis缓存技术系列(三):Redis中的事务和乐观锁如何实现
Redis如何实现事务呢?
1.开启事务和执行事务
C:\Users\Edwin>redis-cli
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379> set name zwl #添加数据
QUEUED
127.0.0.1:6379> set age 25
QUEUED
127.0.0.1:6379> exec # 执行事务
1) OK
2) OK
127.0.0.1:6379> get name#获取数据成功,证明事务执行成功
"zwl"
127.0.0.1:6379> get age
"25"
127.0.0.1:6379>
2.终止事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name lisi
QUEUED
127.0.0.1:6379> set age 26
QUEUED
127.0.0.1:6379> discard # 放弃事务
OK
127.0.0.1:6379> get name
"zwl"
127.0.0.1:6379>
3.异常自动终止事务
3.1 编译异常:全部不执行
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379> set name lisi
QUEUED
127.0.0.1:6379> set age 27
QUEUED
127.0.0.1:6379> set name2 #输入一个错误的命令
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> exec #执行事务,报错,并且所有的命令都不会执行
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> getname
(error) ERR unknown command `getname`, with args beginning with:
127.0.0.1:6379> get age
"25"
127.0.0.1:6379>
3.2 运行异常
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name lisi
QUEUED
127.0.0.1:6379> incr name #对字符串数据进行自增操作,没有立即执行
QUEUED
127.0.0.1:6379> set age 26
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> exec #执行事务。自增操作报错了,其他的命令可以执行的
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) "26"
127.0.0.1:6379> get age
"26"
127.0.0.1:6379> get name
"lisi"
127.0.0.1:6379>
总结:
- Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。
你可能会觉得这种行为很奇怪。然而,这种行为也有其合理之处:事务回滚并不能解决任何程序错误。没有人能解决自己的错误,这种错误可能会导致Redis命令执行失败。所以保留。
Redis如何实现乐观锁呢?
为什么要使用乐观锁,举例下面的问题:
1.在并发的情况下。如果有多个线程对一个数据进行操作,如果我们没有控制好并发,那么可能我们拿到的数据就不是最新的。就可能导致脏读、幻读和不可重复读等问题。所以就可以使用乐观锁。
那么什么是乐观锁,我们可以先讲一下悲观锁。
悲观锁,不管什么情况下都会对数据进行监控,没有执行完当前操作就不允许其他现场使用,比较浪费性能。一般不适用
而乐观锁,只有更新数据的时候,采取判断数据是否被更新过,如果更新过就执行失败。否则正常执行。
那么如何使用呢?需要用到一个watch指令
127.0.0.1:6379> set money 200
OK
127.0.0.1:6379> set cost 0
OK
127.0.0.1:6379> watch money #监控钱这个key
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 100
QUEUED
127.0.0.1:6379> incrby cost 100
QUEUED
127.0.0.1:6379> exec
1) (integer) 100
2) (integer) 100
这样一切正常。
增加两个线程
执行报(nil),因为我们监视了money这个值,如果事务要对这个值进行操作前,监视器会判断这个值是否正常,发生改变则事务执行失败!