Redis的事务和乐观锁实现

事务

Redis事务本质是一组命令的集合,按队列执行。事务中每条命令都会被序列化,执行过程中按顺序执行,不允许其他命令进行干扰。

Redis事务没有隔离级别的概念,Redis单条命令是保证原子性的,但是事务不保证原子性!

Redis的事务操作非常简单,分为下面3步:

  • 开启事务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> set k3 v3
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> keys *
QUEUED
127.0.0.1:6379> EXEC  # 执行事务
1) OK
2) OK
3) OK
4) "v1"
5) 1) "k3"
   2) "k2"
   3) "week"
   4) "k1"

取消事务discard

127.0.0.1:6379> FLUSHDB   # 清空当前数据库
OK
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> DISCARD  # 取消事务
OK
127.0.0.1:6379> EXEC   # 执行事务   报错   没开启事务
(error) ERR EXEC without MULTI
127.0.0.1:6379> get k1   # get k1 发现为空  说明根本没有被执行
(nil)
127.0.0.1:6379> get k2
(nil)

当执行事务的时候也会出现错误,基本是下面两种错误:

1、命令的语法错误(编译时异常)所有的命令都不执行

127.0.0.1:6379> FLUSHDB  # 清空当前数据库
OK
127.0.0.1:6379> MULTI  # 开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v3
QUEUED
127.0.0.1:6379> get k1 k2  # 这个命令明显是错误的,会在你输入的时候报错,单不影响你下面的命令入队
(error) ERR wrong number of arguments for 'get' command
127.0.0.1:6379> EXEC  # 执行失败
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1  # 为空,说明没有被执行
(nil)

2、命令逻辑错误 (运行时异常) 其他命令可以正常执行

127.0.0.1:6379> MULTI  # 开启事务
OK
127.0.0.1:6379> set k1 "v1"  # set一个字符串
QUEUED
127.0.0.1:6379> INCRBY k1 1  # 字符串加一肯定是错的,但是语法是对的
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"
127.0.0.1:6379> get k1 # 尽管执行的时候单条命令报错,但是其他的命令还是执行了,所以redis事务不保持原子性
"v1"

乐观锁

  • 获取version,更新version
  • 在redis里面用watch来实现
正常执行
127.0.0.1:6379> FLUSHDB  # 清空当前数据库
OK 
127.0.0.1:6379> set A 100  # A用户有100元
OK
127.0.0.1:6379> set use 0  # 使用了 0 元
OK
127.0.0.1:6379> WATCH A  # 用watch监视 A 加锁
OK
127.0.0.1:6379> MULTI  # 开启事务
OK
127.0.0.1:6379> DECRBY A 10 # A用户使用了10元
QUEUED
127.0.0.1:6379> INCRBY use 10  # use理所当然的加10元
QUEUED
127.0.0.1:6379> EXEC  # 执行 没问题
1) (integer) 90
2) (integer) 10
模拟多线程执行插队

线程一

127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set use 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY money 20
QUEUED
127.0.0.1:6379> INCRBY use 20
QUEUED

线程一还没有执行,但是线程二在线程一执行前修改了money的数据

127.0.0.1:6379> INCRBY money 20
(integer) 120

然后线程一执行

127.0.0.1:6379> EXEC  # 执行失败
(nil)

注意:每次EXEC执行完毕后,会自动释放锁,也可以以防万一用UNWATCH手动解锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值