对于关系型数据库来说,事务这个面试的时候最开头的就是什么是事务?事务的ACID,事务的隔离级别,当说完可能就讲什么是MVCC机制了等等,
但是在Redis中的事务是没有原子性的,了解Redis的管道机制的小伙伴应该会知道,管道机制主要为了多次提交而发生的读写,通过批量的方式减少命令传输的次数,而Redis的事务就像管道机制提交的命令一样是提交的命令集合,
Redis事务的命令主要是 multi(开启事务) exec(执行事务) discard(丢弃事务)
当我们开启事务后就可以同时执行一组命令,根据顺序一个一个执行,执行成就会返回 QUEUED 看Redis返回的结果为什么会是一个队列意思呢?Redis把开启事务后的命令都存储到了Redis的事务队列里面了,当我们没有执行exec命令的时候这些命令都在队列里面,当执行了就会返回每条命令的执行结果,如图:
image.png看到上面返回的是事务开启后里面命令的返回结果,执行成功就会输出每条命令的结果,失败就会返回 nil 取消就返回 OK
在开启事务需要注意地方:
-
如果事务执行时 命令集合中存在命令的书写错误,那么整个集合的命令都不会被执行
-
不过,从 Redis 2.6.5 开始,服务器会对命令入队失败的情况进行记录
-
并在客户端调用 EXEC 命令时(事务执行命令),拒绝执行并自动放弃这个事务
-
如参数数量错误、参数名错误等等,或者其他更严重的错误,比如内存不足
-
对于这种情况,Redis早些时候会在事务执行前检查命令入队所得的返回值:如果命令入队时返回
QUEUED
,那么入队成功;否则,就是入队失败 -
如果有命令在入队时失败,那么大部分客户端都会停止并取消这个事务
-
如果命令编译通过,异常为运行时异常 那么其他的命令仍会照常执行,存在运行时异常的命令会执行失败
-
比如使用
incy
命令对一个非整形数据进行原子 +1操作 -
事务是可以取消的,如果事务取消 那么这些入队的命令也不会被执行
-
可以手动使用命令取消,也可以直接 ctrl + F4强制取消(在事务未被执行前打断施法即可)
事务的取消:
当我们想取消事务的时候就可以使用 discard丢弃当前事务,这个命令要在exec前执行,因为redis没有回滚的概念。
阿里的一个面试:为什么Redis不支持回滚:
我们使用过关系型数据库的经验就认为,这面试啥呀?一个大大的疑问,而Redis没有回滚的优点:
-
Redis命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
-
因为不需要对回滚进行支持,所以 Redis的内部可以保持简单且快速。
Redis主要认为失败都是使用者造成的所以就没有回滚操作。
在Redis中除了没有原子性外,Redis对事务也没有隔离级别的概念,所以就不会产生我们使用关系型数据库需要关注的脏读,幻读,重复读的问题,
Redis的watch机制实现乐观锁
虽说 Redis不支持直接回滚,但我们可以通过 Redis提供的一个命令来实现回滚
这个命令就是 watch
,该命令可以为 Redis事务提供 check-and-set (CAS)行为。
我们可以使用 watch
命令来监视一个 或多个key,如果被监视的 key在事务执行前被修改过那么本次事务将会被取消,也就是所谓的回滚
只有确保被监视的 key,在事务开始前到执行 这段时间内未被修改过事务才会执行成功(类似乐观锁)
如果一次事务中存在被监视的 key,无论此次事务执行成功与否,该 key的监视都将会在执行后失效 也就是说监视是一次性的。
watch在事务的 运用注意点:
watch要在事务开启之前就监控不然会报错
watch是一次性的
watch开启的客户端端口连接这个客户端对watch的监听就会被取消
看watch的使用
image.png image.png那就会有小伙伴有疑问那Redis的事务有什么用呢?
我认为现阶段Redis事务的作用不大,因为我们看上面的开启事务后每提交一次命令都返回 QUEUED ,所以我们在开启事务的时候会跟 Redis的管道一起使用来减少读写请求次数,而Redis的事务不保证原子性,隔离性,我们谈到什么Redis实现分布式锁的细节的时候就会说加锁时候要保证原子性,解锁的时候原子性也要保证,所以现阶段的Redis的事务原子性都不保证,我感觉作用不太大
网友评论