redis的事务执行顺序:
1、开启事务( multi )
2、命令入队( )
3、执行事务( exec )
2、测试案例
正常执行事务
> multi # 开启事务
OK
===== 命令入队 =====
> set k1 v2
QUEUED
> set k2 v2
QUEUED
> get k2
QUEUED
===== 执行事务 =====
> exec # 执行事务,按照入队顺序一步一步执行,执行一次之后事务就结束了,如果需要重新执行事务需要重新开启,命令入队操作
OK
OK
v2
取消事务
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> get k2
(nil)
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379> set k1 "v1" #设置字符串值
QUEUED
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) OK
2) (error) ERR value is not an integer or out of range #字符串不是整形不能自增,有异常!但是不影响其他事务!
3) OK
4) OK
127.0.0.1:6379> get k2 #依旧可以获取到值
"v2"
编译型异常(命令有错!),事务中所有的命令都不会被执行!
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> getset k3
(error) ERR wrong number of arguments for 'getset' command #这里因为命令有错,但是不会中断事务,所以下面可以继续写
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> exec #执行事务
(error) EXECABORT Transaction discarded because of previous errors. #执行事务报错,所有的命令都不会被执行
127.0.0.1:6379> get k5 #获取值为nil
(nil)
3、watch(监视)
悲观锁:
1、很悲观,认为什么时候都会出问题,无论做什么都会加锁!
乐观锁
1、很乐观,认为什么时候都不会出问题,所以不会上锁,更新数据的时候去判断一下,在此期间是否有人修改这过个数据
2、获取 version
3、更新的时候比较 version
锁测试
正常执行成功的情况
127.0.0.1:6379> set money 100 #设置零花钱为100
OK
127.0.0.1:6379> set out 0 #设置已经花出去的钱为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