Redis事务常用命令以及通过watch命令实现乐观锁示例

事务:

Redis的单条命令是支持事务的,但是事务不保证原子性。

Redis没有隔离级别的概念,所有的命令在事务中并没有直接去执行,只有发起执行命令的时候才执行。

Redis事务:

  • 开启事务(multi)
  • 命令入队(…)
  • 执行事务(exec)

**Redis事务特点:**一致性,顺序性,排他性。

执行事务命令:

127.0.0.1:6379> multi           #开启事务
OK
127.0.0.1:6379> set myset v1    #命令入队
QUEUED
127.0.0.1:6379> set myset v2    #命令入队
QUEUED
127.0.0.1:6379> get myset       #命令入队
QUEUED
127.0.0.1:6379> set myset v3    #命令入队
QUEUED
127.0.0.1:6379> exec           #执行事务
1) OK
2) OK
3) "v2"
4) OK
127.0.0.1:6379>

放弃事务命令:

127.0.0.1:6379> multi           #开启事务
OK
127.0.0.1:6379> set v1 v1       #命令入队
QUEUED
127.0.0.1:6379> set v2 v2       #命令入队
QUEUED
127.0.0.1:6379> DISCARD         #放弃事务
OK
127.0.0.1:6379> get v1          #取消事务后set的命令没有被执行,对象获取是不到的
(nil)
127.0.0.1:6379>

编译型异常:(代码命令有误),事务中所有的命令都不会被执行。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set v1 v1
QUEUED
127.0.0.1:6379> set v2 v2
QUEUED
127.0.0.1:6379> getset k3        #错误的命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set v3 v3
QUEUED
127.0.0.1:6379> exec             #执行事务会报错,所有的命令是不会被执行的
(error) EXECABORT Transaction discarded because of previous errors.
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> incr k1        #出现语法异常,字符串是不能incr的
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k3
QUEUED
127.0.0.1:6379> exec           #执行事务时incr k1命令就会抛出异常,其他命令正常执行
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) "v3"
127.0.0.1:6379> get k1         #能正常获取到没抛异常的对象
"v1"
127.0.0.1:6379> get k3
"v3"
127.0.0.1:6379>

所以由此看出在redis中事务是不能保证原子性的。

监控:watch
悲观锁:

  • 很悲观,认为什么时候都有可能会出现问题,无论做什么都会加锁!

乐观锁:

  • 很乐观,什么时候都不会出现问题,所以不会上锁!更新数据的时候判断一下在此期间是否有人修改过此数据。
  • 获取version
  • 更新的时候比较version

Redis监视设置:

127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> set cost 0
OK
127.0.0.1:6379> watch money      #监视money对象
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 200
QUEUED
127.0.0.1:6379> incrby cost 200
QUEUED
127.0.0.1:6379> exec            #事务正常结束。数据期间没有变动,则执行成功!
1) (integer) 800
2) (integer) 200
127.0.0.1:6379>

测试多客户端修改值,使用watch可以当做redis的乐观锁 操作!
客户端1监视money:

127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> set cost 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 200
QUEUED
127.0.0.1:6379> incrby cost 200
QUEUED

客户端2修改money的数据:

27.0.0.1:6379> get money
"1000"
127.0.0.1:6379> set money 2000
OK
127.0.0.1:6379>

这时候客户端1再执行事务就会失败!

127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> set cost 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 200
QUEUED
127.0.0.1:6379> incrby cost 200
QUEUED
127.0.0.1:6379> exec       #由于客户端2修改了money的值,这时候exec就会失败!
(nil)
127.0.0.1:6379>

如果事务执行失败了就unwatch(放弃监视)先解锁,然后再次监视money,获取最新的值。

127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> set cost 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 200
QUEUED
127.0.0.1:6379> incrby cost 200
QUEUED
127.0.0.1:6379> exec
(nil)
#以上是客户端1监视时执行失败的结果,事务执行失败就放弃监视,然后重新监视该值,
#并获取该对象最新的值
127.0.0.1:6379> unwatch      #放弃监视
OK
127.0.0.1:6379> watch money  #重新监视
OK
127.0.0.1:6379> get money    #查看当前money的值,因为客户端2修改了money为2000
"2000"
127.0.0.1:6379> multi        #开启事务
OK
127.0.0.1:6379> decrby money 300
QUEUED
127.0.0.1:6379> incrby cost 300
QUEUED
127.0.0.1:6379> exec         #执行事务
1) (integer) 1700
2) (integer) 300
127.0.0.1:6379>

redis乐观锁应用场景:商品秒杀

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Silence-wen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值