6-Redis事务与锁

6-Redis事务与锁,第1张

事务

ACID 要么同时成功 要么同时失败

事务等于一组命令的集合

相当于一组命令的队列 事务中的所有命令都会被序列化

会按照顺序 一次性 顺序执行 ,执行过程中不会被打断。

Redis的事务没有隔离级别的概念 所以不会出现传统数据库隔离级别(脏读、幻读、不可重复读)等情况

Redisa单条命令保证原子性 Redis事务不保证原子性。

所有的redis命令在事务中 并没有被直接执行,只有真正执行到这条命令的时候才执行

redis 事务:

  1. 开启事务(multi)
  2. 命令入队(具体命令)
  3. 执行事务(exec)
开启一个事务
127.0.0.1:6379> MULTI #开启事务
OK
127.0.0.1:6379> set key1 v1
QUEUED #进入队列
127.0.0.1:6379> set key2 v2
QUEUED
127.0.0.1:6379> get key1
QUEUED
127.0.0.1:6379> set key3 v3
QUEUED
127.0.0.1:6379> exec #执行事务
1) OK #key1 v1 创建成功
2) OK #key2 v2 创建成功
3) "v1"  #get key1
4) OK #key3 v3创建成功
取消一个事务

执行完了 这个事务就没有了 如果需要 需要再次开启

127.0.0.1:6379> MULTI #上面执行完成事务就没有了  需要再次开启事务
OK
127.0.0.1:6379> set key1 v1
QUEUED #进入队列
127.0.0.1:6379> set key2 v2
QUEUED
127.0.0.1:6379> set key5 v5
QUEUED
127.0.0.1:6379> DISCARD #取消事务
OK
127.0.0.1:6379> get key4 #key4 没有创建成功
(nil)
事务语法错误

整个事务不会被执行 有点像java的编译错误 代码语法有问题 编译不通过 不会生成.class文件

整个都不会编译成功

127.0.0.1:6379> MULTI #开启事务
OK
127.0.0.1:6379> set key1 v1
QUEUED #进入队列
127.0.0.1:6379> set key2 v2
QUEUED
127.0.0.1:6379> getou key3 v3 #队列中有一个命令是错误的
(error) ERR unknown command `getou`, with args beginning with: `key3`, `v3`, 
127.0.0.1:6379> set key4 v4
QUEUED
127.0.0.1:6379> exec #执行事务的时候报错 整个事务不会被执行
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get key1 #  查询不到创建结果  所有命令没有执行
(nil)
事务逻辑错误

语法没问题 逻辑上的问题 只有逻辑错误的语句不执行,其它语句正常执行

像java运行错误,比如内存溢出问题 编译的时候不会出问题 运行也不会出问题 只有当内存真的溢出了才会有故障。

127.0.0.1:6379> MULTI #开启事务
OK
127.0.0.1:6379> set key1 "测试"
QUEUED #进入队列
127.0.0.1:6379> incr key1 #key1自增 这个是错误的 字符串没法自增
QUEUED
127.0.0.1:6379> set key2 v2
QUEUED
127.0.0.1:6379> set key3 v3
QUEUED
127.0.0.1:6379> get key3
QUEUED
127.0.0.1:6379> exec # 执行事务
1) OK
2) (error) ERR value is not an integer or out of range #只有自增是错误未执行  其它执行了
3) OK
4) OK
5) "v3"
127.0.0.1:6379> get key3 #可以查询到key3的值
"v3"
127.0.0.1:6379> 
监控watch
  1. 悲观锁 认为一直都会出问题 比较谨慎 做什么都先加锁 性能比较差

  2. 乐观锁 认为一直都不会出问题 所以不会上锁 更新数据的时候判断一下 是否有人修改过数据

    2.1 获取version

    2.2 更新的时候比较version

   127.0.0.1:6379> set num 1000
   OK
   127.0.0.1:6379> set outmum 0
   OK
   127.0.0.1:6379> watch num #开启监控
   OK
   127.0.0.1:6379> MULTI #开启事务
   OK
   127.0.0.1:6379> DECRBY mun 20
   QUEUED
   127.0.0.1:6379> INCRBY outmun 20
   QUEUED
   127.0.0.1:6379> exec #事务正常执行
   1) (integer) -20
   2) (integer) 20
   127.0.0.1:6379> 

   127.0.0.1:6379>  set num 1000
   OK
   127.0.0.1:6379> set outnum 0
   OK
   127.0.0.1:6379> watch num
   OK
   127.0.0.1:6379> MULTI
   OK
   127.0.0.1:6379> DECRBY money 30
   QUEUED
   127.0.0.1:6379> INCRBY outnum 30
   QUEUED
   127.0.0.1:6379> 

窗口2在窗口一事务还未执行的情况下 修改了num

   127.0.0.1:6379> get num
   "1000"
   127.0.0.1:6379> set num 100
   OK
   127.0.0.1:6379> 

返回窗口1 执行事务失败返回nil

结论:在执行事务之前 另外一个线程修改了我们需要的值 这时候会导致事务执行失败

乐观锁

利用watch命令监听key,实现乐观锁 应用场景比如秒杀来防止超卖

   127.0.0.1:6379>unwatch  #如果执行失败  就先解锁
   OK
   127.0.0.1:6379>watch num  #在重新上锁 获取最新的值
   OK
   127.0.0.1:6379> MULTI #开启事务 以上三步 如果失败  重新 *** 作
   OK
   127.0.0.1:6379> DECRBY money 30
   QUEUED
   127.0.0.1:6379> INCRBY outnum 30
   QUEUED
   127.0.0.1:6379> exec

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/721712.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存