redis事务锁


事务介绍

Redis的事务与关系型数据库中的事务区别

1)在MySQL中讲过的事务,具有A、C、I、D四个特性
	Atomic(原子性)
	# 所有语句作为一个单元全部成功执行或全部取消。
	Consistent(一致性)
	# 如果数据库在事务开始时处于一致状态,则在执行该。事务期间将保留一致状态。
	Isolated(隔离性)
	# 事务之间不相互影响。
	Durable(持久性)
	# 事务成功完成后,所做的所有更改都会准确地记录在数据库中。所做的更改不会丢失。

2)MySQL具有MVCC(多版本并发控制)的功能,这些都是根据事务的特性来完成的。

3)redis中的事务跟关系型数据库中的事务是一个相似的概念,但是有不同之处。关系型数据库事务执行失败后面的sql语句不在执行前面的操作都会回滚,而在redis中开启一个事务时会把所有命令都放在一个队列中,这些命令并没有真正的执行,如果有一个命令报错,则取消这个队列,所有命令都不再执行。

4)redis中开启一个事务是使用multi,相当于begin\start transaction,exec提交事务,discard取消队列命令(非回滚操作)。
mysql redis
开启 start transaction begin multi
语句 普通SQL 普通命令
失败 rollback回滚 discard取消(这里的取消不是回滚,是队列里的命令根本没有执行,并不是执行了之后,再撤回)
成功 commit exec

事务相关命令

1)DISCARD
取消事务,放弃执行事务块内的所有命令。
2)EXEC
执行所有事务块内的命令。
3)MULTI
标记一个事务块的开始。
4)UNWATCH
取消 WATCH 命令对所有 key 的监视。
5)WATCH key [key ...]
监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

事务测试

#登录redis
[root@db01 ~]# redis-cli
#验证密码
127.0.0.1:6379> auth 123
OK
#不开启事务直接设置key
127.0.0.1:6379> set zls "Nice"
OK
#查看结果
127.0.0.1:6379> get zls
"Nice"
 
#开启事务
127.0.0.1:6379> MULTI
OK
#设置一个key
127.0.0.1:6379> set bgx "low"
QUEUED
127.0.0.1:6379> set alex "Ugly"
QUEUED
#开启另一个窗口查看结果
127.0.0.1:6379> get bgx
(nil)
127.0.0.1:6379> get alex
(nil)
 
#执行exec完成事务
127.0.0.1:6379> EXEC
1) OK
2) OK
 
#再次查看结果
127.0.0.1:6379> get bgx
"low"
127.0.0.1:6379> get alex
"Ugly"

image-20240719094355757

redis乐观锁介绍

乐观锁举例

场景:我正在买票
Ticket -1 , money -100

而票只有1张, 如果在我multi之后,和exec之前, 票被别人买了---即ticket变成0了.
我该如何观察这种情景,并不再提交?

1)悲观的想法:
世界充满危险,肯定有人和我抢, 给 ticket上锁, 只有我能操作. [悲观锁]

2)乐观的想法:
没有那么人和我抢,因此,我只需要注意,
--有没有人更改ticket的值就可以了 [乐观锁]

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

乐观锁实现

#####  模拟买票  ####
	
#首先在第一个窗口设置一个key(ticket 1)
127.0.0.1:6379> set ticket 1
OK
#设置完票的数量之后观察这个票
127.0.0.1:6379> WATCH ticket
OK
#开启事务
127.0.0.1:6379> MULTI
OK
#买了票所以ticket设置为0
127.0.0.1:6379> set ticket 0
QUEUED
#然后在第二个窗口观察票
127.0.0.1:6379> WATCH ticket
OK
#开启事务
127.0.0.1:6379> MULTI
OK
#同样设置ticket为0
127.0.0.1:6379> set ticket 0
QUEUED
#此时如果谁先付款,也就是执行了exec另外一个窗口就操作不了这张票了
#在第二个窗口先付款(执行exec)
127.0.0.1:6379> exec
1) OK
#然后在第一个窗口再执行exec
127.0.0.1:6379> exec
(nil)       //无,也就是说我们无法对这张票进行操作

image-20240719094412898