Redis 事务是什么?又和MySQL事务有什么区别?

目录

1. Redis 事务的概念

2. Redis 事务和 MySQL事务的区别?

3. Redis 事务常用命令


1. Redis 事务的概念

下面是在 Redis 官网上找到的关于事务的解释,这里划重点,一组命令,一个步骤。

也就是说,在客户端与 Redis 交互的时候,一个步骤中执行一组命令,它们按照顺序执行而且执行过程中不会被其他命令加塞,必须一起执行完毕,就是 Redis 事务。

比如下面这两个 set 指令,本质上来说其实是和 Redis 交互的两次,所以它们其实是两次事务。

127.0.0.1:6379> set name1 "zhangsan"
OK
127.0.0.1:6379> set name2 "lisi"
OK

2. Redis 事务和 MySQL事务的区别?

(1)单独的隔离操作

Redis 事务仅仅保证事务里的操作会被连续独占的执行,Redis 命令执行是单线程架构,在执行事务内所有命令请求之前无法去执行其他客户端请求;

(2)没有隔离级别的概念

Redis 事务在提交之前任何指令都不会实际的被执行,所以不存在MySQL中脏写,脏读,不可重复读,幻读等问题;

(3)不保证原子性

Redis 事务不保证原子性,Redis 不能保证所有指令同时成功和失败,只能保证事务的指令一同执行,因为对于 Redis 来说,事务回滚带来的代价太大,影响性能;所以对于一个 Redis 事务来说,是有可能出现部分指令执行成功但部分指令执行失败的;

(4)排它性

Redis 在执行事务的过程中,能保证事务内的命令依次执行不被其他命令插入;

3. Redis 事务常用命令

MULTI:标记一个事务快的开始;

EXEC:执行事务块中的所有命令;

DISCARD:取消事务,放弃执行事务块中的所有命令;

UNWATCH:取消 WATCH 命令对所有 key 的监控;

WATCH key [key...]:监控一个或多个key,如果事务执行之前这些key被其他事务改动,事务就会被打断;

示例1(事务正常提交)

使用 multi 命令开始一个事务,可以看到客户段上都标记有 "TX" 事务的标志,在陆续添加 k1,k2,k3之后,并没有显示执行成功,而是返回一个QUEUED,这是队列的意思,也就是说开启事务之后,Redis 将所有需要的命令放到了一个队列中,在执行 EXEC 操作之后,会将队列中的命令全部执行;

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
"v3"

示例二(取消事务): 

先存放一个 age 为24的值,然后开启事务,在使用DISCARD取消事务命令,我们再次 get age,取到的还是原来的 24,不是事务中希望添加的 20,即事务未执行。

127.0.0.1:6379> set age 20
OK
127.0.0.1:6379> mulit
(error) ERR unknown command 'mulit', with args beginning with: 
127.0.0.1:6379> set age 24
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set age 20
QUEUED
127.0.0.1:6379(TX)> discard
OK
127.0.0.1:6379> get age
"24"

示例三(EXEC 之前错误,类似于编译时异常):

其实这个有点类似于 Java 中的编译时异常,就是再添加命令到事务队列中的时候命令是错的,redis 会检查出来,并将队列中的所有操作全部返回,就是不执行的意思,不是回滚,回滚是执行过但是又退回来,这里是根本没有执行,小伙伴们一定要分清楚哦

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set name jack
QUEUED
127.0.0.1:6379(TX)> set username
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
// EXCEABORT翻译过来就是打断EXEC提交命令
127.0.0.1:6379> get name
(nil)

示例四(EXEC 之后出现错误,类似于运行时异常):

第一步,开启一个事物,存放一个数字类型的值num1和字符串的值email;

第二步,get 获取 num1 和 email ,能获取到,说明存放成功;

第三步,对num1使用 incr 命令使其自增1,对 email 也是用 incr 命令使其自增1;

从语法上来讲,所有命令本身并没有错误,所以 redis 是检查不出来的,但是在逻辑上我们不能让字符串类型的数据自增1,所以 incr email 这个命令时执行失败的,但是其他命令都没有问题,是可以正常执行的,这就是 redis 于 MySQL最大的区别,MySQL是同成功同失败,redis 则是能执行成功的就会保存不进行回滚,执行失败的那就是失败了。

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set num1 1000
QUEUED
127.0.0.1:6379(TX)> set email 12345@qq.com
QUEUED
127.0.0.1:6379(TX)> get num1
QUEUED
127.0.0.1:6379(TX)> get email
QUEUED
127.0.0.1:6379(TX)> incr num1
QUEUED
127.0.0.1:6379(TX)> incr email
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) "1000"
4) "12345@qq.com"
5) (integer) 1001
6) (error) ERR value is not an integer or out of range

补充一点:WATCH 底层采用的是CAS乐观锁,如果我们使用WATCH监控了一些 key,那么在事务中在执行修改这些被监控的 key 数据的时候,会判断当前 key 的值是否与期望值一样,如果一样就会做修改,如果不一样就会放弃修改,当前整个事务的操作都会放弃执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值