我们知道熟悉MySQL的同学,一定了解ACID属性。ACID分别对应四种属性,但是Redis的事务和ACID属性有什么不一样的地方嘛,我们来深入探讨下。
Redis事务和MySQL事务的区别
ACID的本质是保证了事务执行前后对结果的保证,以及数据状态变化的保证。MySQL通过日志、MVCC、隔离级别、锁等机制实现ACID。
但是Redis并不是传统意义上的事务级别,Redis的事务本质是可以一次执行多条命令、并且在这个事务中会序列化执行,按照顺序串行化执行而不会被其他命令插入,不许加塞。
Redis事务原理
具体命令
执行流程
- 1.客户端会显示的使用MULTI声明事务开始,
- 2.客户端发送对数据的操作,增删改查,然后Redis服务端接受之后会暂存到一个命令队列中,这个时候并不会执行。
- 3.当客户端发送EXEC命令之后,服务端会从命令队列中按照顺序取出来,执行。
正常执行
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set key1 v1
QUEUED
127.0.0.1:6379(TX)> set key2 v2
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK
2) OK
原子性
上面在正常的情况下,MUTI 和 EXEC 都会被正常执行可以保证原子性。
1.在提交命令的时候,如果命令本身就是错误的
显然执行之后,直接抛出错误,可以保证原子性
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> put het 1
(error) ERR unknown command `put`, with args beginning with: `het`, `1`,
127.0.0.1:6379(TX)> set key3 v3
QUEUED
127.0.0.1:6379(TX)> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379>
2.提交命令时,命令和数据类型不符合,在执行的时候异常
在对key1 进行减1操作的时候执行出错,但是后续的命令却成功了,显然这没有保证原子性。属于一半执行成功,一半执行失败。
在MySQL中,提供了回滚操作,但是在Redis中虽然提供了DISCARD 主动放弃事务,把命令队列清空,起不到数据回滚的作用。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> DECR key1
QUEUED
127.0.0.1:6379(TX)> set key6 v6
QUEUED
127.0.0.1:6379(TX)> EXEC
1) (error) ERR value is not an integer or out of range
2) OK
127.0.0.1:6379>
3.在执行事务exec Redis实例发生了故障,导致事务执行失败
如果Redis故障了,我们开启了AOF机制,那么可以通过AOF恢复实例宕机之前的数据,但是如果没有开启,无法保证原子性。
- 命令入队就出错的话,会放弃整个事务,可以保证原子性。
- 命令入队在执行的时候出错的话,不保证原子性
- EXEC命令执行故障,开启AOF日志,可以保证原子性。
一致性
数据一致性其实就在执行前后,是否会保证数据状态的一致性,而上述原子性中,可以发现,出了对出现错误的命令不会执行,剩下情况其实是可以保证数据一致性的。
隔离性
事务的隔离性与事务并发修改数据有关系,而事务执行时机又可以分为命令入队(EXEC执行前),命令执行后(EXEC执行后)
- 并发操作在EXEC执行前,需要使用WATCH机制进行保证,否则隔离性无法保证。
- 并发操作在EXEC执行后,隔离性可以保证。
第一种情况
我们知道当命令在队列中时,是没有执行命令,这个时候如果有别的线程修改对应的队列中命令字段对应的数据值,就无法保证隔离性。但是使用WATCH机制可以保证,WATCH机制的原理是通过在命令入队之前,监控对应的键是否修改,如果修改,那么在EXEC执行时就会异常。
具体就是EXEC值执行发现WATCH监听的数据有修改,就是放弃执行。但是如果没有WTCH机制,exec队列中命令也会读取最新的值,但是这样其实没有办法保证隔离性。
第二种方式,exec执行之后
因为redis是单线程执行,所以会先保证把命令队列中所有命令执行完,所以这种方式也不会破坏事务的隔离性。
持久性
持久性其实就依赖于Redis的AOF和RDB机制,而不同的持久化方式,也无法完全百分百保证数据一定会被持久化,RDB有一定的频率执行,而Redis虽然可以使用always模式,但是如果正好写入内存的数据没有刷到pageCache中,也没有办法进行数据持久化。
总结
本篇主要介绍了Redis的事务在ACID中不同的实现,综合分析,我们可以得出一个结论,Redis事务只保证了一致性和隔离性,但是无法保证持久性,并且Redis是一个缓存中间件,大多数的时候,业务上其实可以容许出现数据丢失的情况。