【redis】redis事物和锁

1、redis事物

1.1、redis事物的特性

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

具有一致性、隔离性、持久性,但是没有原子性

redis单调命令保证原子性,但是事物没有原子性

redis的事物

  • 开启事物(multi)
  • 命令入队(...)
  • 执行事物(exec)

1.2、事物实现

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> set k3 v3
QUEUED
127.0.0.1:6379> exec  #提交事物
1) OK
2) OK
3) "v1"
4) OK
127.0.0.1:6379> set k1 v2
QUEUED
127.0.0.1:6379> discard  #放弃修改
OK
127.0.0.1:6379> get k1
"v1"

当事物出现编译型异常的时候(代码有问题,命令有错),所有的命令都不会执行

如果是运行时候出现语法错误,错误命令抛出异常,但是其他命令正常执行,这就是没有原子性的表现!

#语法审查不过关
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> qwe
(error) ERR unknown command `qwe`, with args beginning with:
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

#出现逻辑错误的时候,抛出异常
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 "v1"
QUEUED
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) "v1"

2、redis实现乐观锁、悲观锁

2.1、先看看没有锁带来的并发问题:

线程1

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby out 10
QUEUED

线程2


127.0.0.1:6379> decrby money 10
(integer) 90

线程1提交之后

127.0.0.1:6379> exec
1) (integer) 80  #被其他线程影响
2) (integer) 10

出现了脏数据,其实mysql这样的关系型数据库通过隔离级别来解决,而redis没有隔离级别一说,直接通过底层的锁来实现:

2.1、乐观锁

127.0.0.1:6379> watch money #通过watch实现乐观锁
OK

加上乐观锁,上面的线程1提交之后就会

127.0.0.1:6379> exec
(nil) #提交失败

提交失败之后怎么办呢?

127.0.0.1:6379> unwatch money #放弃监视
OK
127.0.0.1:6379> watch money #重新监视
OK
(然后再次执行操作)

发现没有,其实就是自旋,不对不一样,重新获取最新值(放弃监视然后再监视)


【小结】

一般秒杀这样的场景会用到redis里面的乐观锁

posted @ 2022-05-19 20:56  吴承勇  阅读(33)  评论(0编辑  收藏  举报