zoukankan      html  css  js  c++  java
  • Redis——事务与乐观锁

    Redis——事务与乐观锁

    事务:要么同时成功,要么同时失败。

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

    Redis事务本质:一组命令的集合。一个事务中的所有命令都会被序列化。在事务执行的过程中,会按照顺序执行,并且不允许被别人干扰的。

    总结:一次性、顺序性、排他性。执行一系列的命令。

    -------- 队列 set set set 执行 --------
    

    Redis事务没有隔离级别的概念。

    所有的命令在事务中,并没有直接被执行。只有发起执行命令的时候才会执行。Exec。

    redis的事务:

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

    正常执行事务

    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 k2		# 命令入队
    QUEUED
    127.0.0.1:6379> exec		# 执行事务
    1) OK
    2) OK
    3) "v2"
    

    放弃事务:DISCARD

    一旦放弃事务,队列中的所有任务全都不会执行了。

    127.0.0.1:6379> set k1 v1
    QUEUED
    127.0.0.1:6379> set k2 v2
    QUEUED
    127.0.0.1:6379> set k4 v4
    QUEUED
    127.0.0.1:6379> DISCARD		# 取消事务
    OK
    127.0.0.1:6379> get k4		# 事务中的命令都不会执行
    (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> xxxget v3	# 错误的命令
    (error) ERR unknown command `xxxget`, with args beginning with: `v3`, 
    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> get k1
    (nil)
    

    类似于运行时异常,计算(1/0)会报错。如果事务队列中存在语法性错误,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常。

    127.0.0.1:6379> set k1 "v1"
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> INCR k1
    QUEUED
    127.0.0.1:6379> set k2 v2
    QUEUED
    127.0.0.1:6379> set k3 v3
    QUEUED
    127.0.0.1:6379> EXEC	# 虽然执行的时候报错了,但是整个事务依旧正常执行成功了
    1) (error) ERR value is not an integer or out of range
    2) OK
    3) OK
    127.0.0.1:6379> MGET k1 k2
    1) "v1"
    2) "v2"
    

    单条命令是可以保证原子性的,事务是不保证原子性的。

    Redis监控

    悲观锁:

    • 很悲观,认为什么时候都会出问题,无论做什么都会加锁。

    乐观锁:

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

    redis测试监视测试

    正常情况

    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		# 监视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> watch money		# 监视money对象
    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
    

    进程二:

    127.0.0.1:6379> set money 100
    OK
    

    回到进程一:

    127.0.0.1:6379> exec			
    (nil)
    # 执行之前,另外一个进程修改了money这个对象的值,这个时候,就会导致事务执行失败
    

    发现这里返回nil,也就是修改失败。

    测试其他进程修改值,使用watch可以当作redis的乐观锁操作。

    如果发现事务执行失败,就先解锁。需要操作的时候,就重新再监视(watch)

    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 10
    QUEUED
    127.0.0.1:6379> INCRBY out 10
    QUEUED
    127.0.0.1:6379> exec			# 比对监视的值是否发生了变化,如果变化,执行失败,否则,正常执行
    1) (integer) 90
    2) (integer) 30
    

    如果修改失败,重新获取最新的值在操作就好了。

  • 相关阅读:
    Swagger UI教程 API 文档神器 搭配Node使用 web api 接口文档 (转)
    C#测试web服务是否可用(转)
    使用Fiddler测试WebApi接口
    .Net 序列化(去除默认命名空间,添加编码)
    Win10 下Cisco AnyConnect Secure Mobility Client问题(转)
    jQuery.extend 函数详解(转)
    Oracle 取Group By 第一条
    EFProf用法
    c#和JS数据加密(转)
    C#中字符数组,字节数组和string之间的转化(转)
  • 原文地址:https://www.cnblogs.com/liuhuan086/p/13583810.html
Copyright © 2011-2022 走看看