NoSQL数据库Redis支持的简单事务

  Redis作为一个数据库,也提供了比较简单的事务操作来保证原子性,首先来对比一下Redis和传统数据库Mysql的事务操作:

数据库 mysql redis
开启 start transaction multi
语句 sql语句 redis命令
失败 rollback 回滚 discard 取消
成功 commit 提交 exec 执行

Redis的一个事务从开始到执行会经历以下三个阶段:开始事务 ---》命令入队 ---》 执行事务。首先看一个正确的Redis事务:

从截图中可以看出,使用multi开启事务,实际上是把命令存入一个QUEUE当中,使用exec来执行QUEUE当中的命令,而使用discard会舍弃QUEUE当中的命令。

不过Redis的事务,不像mysql那样,保证绝对的原子性,要么都成功,要么都失败。因为在使用Redis事务的时候,收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行,在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。这样就保证不了原子性了,也是一个坑呀!下面举例说明:

1、写入的redis命令有错误

tmd不是Redis中的命令,当执行这个tmd时会报错,导致QUEUE当中的命令得不到执行,相当于mysql中的回滚,这还好,也相当程序正常运行了!

2、写入的redis命令没有错误,但是执行的对象有问题

可以看出,虽然QUEUE执行命令当中有一句命令是错误的,但是其他的操作还可以正常进行,并没有回滚或者是取消,有问题吧!这种命令问题怎么避免的,我想还是我们搬砖者本身提高代码质量吧!

3、多线程操作Redis的并发问题,春节将至,我们就举抢票的例子吧!

按照上面数字标注的顺序:123来执行,可以看到Redis的事务并没有提供隔离性,在一个事务exec之前,另外一个事务提前exec了,这就照成了票数将为-1,这肯定不符合实际。

有问题的出现,就要有解决方案的出现。Redis针对没有隔离性这一说,提供了watch的机制,相当于乐观锁一样,如果一个key被监视,那么在Redis执行exec命令之前会检查这个被监视的key有没有改动过,改过就取消执行。

这次我们对ticket加了watch进行监视,叫“fu”的那个人网速还是比我快,提前把票抢走了,但是我这边再进行exec提交就没那么尴尬了,票数是0没有变为-1,钱也没扣我的。

综上,单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。如果还想保证像关系型数据库那样的隔离性(其实不是隔离性,只是一个监视),还要配合watch命令对要操作的key进行一个监视,取消监视就用unwatch命令!

猜你喜欢

转载自blog.csdn.net/Apeopl/article/details/84875054
今日推荐