Redis:事务

引用学习:https://space.bilibili.com/95256449/

描述

Redis 事务本质:一个事务就是一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中按照顺序执行!

 

特性

Reids事务保证:一次性、顺序性、排他性!执行一系列的命令!

一次性:只有当所有的命令进入队列后,再一次性执行。

顺序性:按照进入队列的先后顺序执行,先进先出。

排他性:事务在执行过程中,是不允许被干扰的。

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

 

注意点:

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

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

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

 

Redis的事务,需要做3步:

  1. 开启事务(multi)

  2. 命令入队(...)

  3. 开启事务(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> set k3 v3
QUEUED
127.0.0.1:6379> exec    # 执行事务
1) OK
2) OK
3) "v2"
4) 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> set k3 v3
QUEUED
127.0.0.1:6379> discard    # 取消事务
OK
127.0.0.1:6379> get k3    # 事务队列中的命令都取消了,不会执行!
(nil)

编译型异常(代码有问题!命令有错的时候!)

  • 事务中的所有命令都不会被执行!
127.0.0.1:6379> multi    # 开启事务
OK
127.0.0.1:6379> set k1 v1 k2 v2 k3 v3
QUEUED
127.0.0.1:6379> getset k3    # getset key value,故意制造编译的错误
(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)

运行时异常(比如: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> get k3
QUEUED
127.0.0.1:6379> exec    # 只有错误语法的命令会报错,其他正常执行
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
4) "v3"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k1
"v1"

Redis 监视

正常执行

正常执行成功!

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    # 余额减少 20
QUEUED
127.0.0.1:6379> incrby out 20    # 转出的钱 +20
QUEUED
127.0.0.1:6379> exec    # 执行事务,如果数据期间没有发生变化,这个时候就正常执行成功!
1) (integer) 80
2) (integer) 20

测试多线程修改值,使用watch 可以当做redis乐观锁操作!

1、一个线程正在执行事务

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

2、另一个线程插队,将money的值修改为200

[root@zxh bin]# redis-cli -p 6379
127.0.0.1:6379> get money
"100"
127.0.0.1:6379> set money 200    # 插队,将值修改
OK

3、再执行之前的事务

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    # 在执行之前,会进行对比,发现另一个线程修改了我们的值,这个时候,就会导致事务执行失败!
(nil)

如果修改失败,获取最新的值就好了

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 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 180
2) (integer) 20

 

posted @ 2020-06-06 14:18  忘忧山的兰木  阅读(234)  评论(0编辑  收藏  举报
她只是想吃这个而已啊……这一定是她非常爱吃的,我居然连如此细微的幸福也夺走了……
Hide
Switch
Save