事务&乐观锁

225 阅读2分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

事务

要么同时成功,要么同时失败,原子性!

redis单条命令是保证原子性,但是事物是不保证原子性的!

有发起执行命令的时候才会执行

一次性、顺序性、排他性

Redis事物本质:一组命令的集合!,一个事物中的所有命令都被序列化,在事务执行过程中会按照顺序执行

redis事务没有隔离级别的概念

所有的命令在事务中并没有直接被执行,只

redis事务

开启事务 # multi
​
命令入队  #set key1 v1 
​
执行事务 #exec
​
正常执行事务
​
放弃事务  #discard
​
​

例子

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "v1"
127.0.0.1:6379>

异常

编译型异常(代码有问题!命令有错!)事务中所有命令都不会被执行!

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> setget k2
(error) ERR unknown command `setget`, with args beginning with: `k2`, 
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k3
(nil)
​

运行时异常如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 "v2"
QUEUED
127.0.0.1:6379> incr k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) (error) ERR value is not an integer or out of range
4) OK
127.0.0.1:6379> get k3
"v3"
127.0.0.1:6379>

redis实现乐观锁(面试常问)

redis实现乐观锁(面试常问)

悲观锁:

无论做什么都加锁

乐观锁:

获取version

很乐观,认为什么时候都不会出现问题,所以不会上锁。更新数据的时候去判断一下,在此期间是否修改过这个数据,watch

Redis监视测试

unwatch 放弃监视 解锁

watch money重新监视

如果发现事务执行失败就先解锁,获取最新的值再次监视执行事务,exec比对监视的值是否发生变换如果没有变换执行成功,如果变换了执行失败

事务执行成功

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money 
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20
127.0.0.1:6379>

模拟两个线程,一个线程修改了事务中的数据,事务执行失败

线程一

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money  #监视数据上锁
OK
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec  #执行事务的时候 判断money值发现改变(被线程2修改为1000)事务执行失败
(nil)                 
127.0.0.1:6379> unwatch  #先解锁
OK
127.0.0.1:6379> watch money  #在上锁重新执行事务
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 980
2) (integer) 20
127.0.0.1:6379> 

线程二

127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379>