redis的事务
什么是事务
事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。它有4个特性:
- 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行[3]。
- 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束[3]
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行[3]。
- 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中[3]。
Redis的事务
Redis如何开启事务
redis开启事务主要有如下4个命令:MULTI
、EXEC
、DISCARD
、 WATCH
。
命令 | 作用 |
---|---|
MULTI |
显式的开启事务,之后的命令将被缓存在命令队列里面,入队的时候会对命令进行检查,命令错误就入队失败,直到使用EXEC 命令才一起执行, |
EXEC |
执行事务中的commands 队列,恢复连接状态。如果在watch 之前被调用,只有监测中的Keys 没有被修改,命令才会被执行,否则停止执行 |
DISCARD |
清空事务中的commands 队列,恢复连接状态,如果有使用watch 命令监控key 的话,监控状态将被取消 |
WATCH |
将给出的Keys 标记为监测态 ,作为事务执行的条件,一旦一个被监控的键被改了,事务将执行失败 |
Redis事务是真正的事务么?满足ACID么?
原子性:redis通过
commands
队列的实现,要么队列里面的全部执行要么全部不执行,这个满足原子性。值得注意的是,redis在执行队列里面的命令在执行的时候有某一条发生错误的时候,redis并不会进行回滚(rollback),官方解释是:- Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
- 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。
鉴于没有任何机制能避免程序员自己造成的错误, 并且这类错误通常不会在生产环境中出现, 所以 Redis 选择了更简单、更快速的无回滚方式来处理事务。
一致性:redis有三个地方有可能执行事务出错,redis都进行了妥善的处理保证其一致性。
入队错误:在命令进入
commands
队列的时候,会检查命令的合法性,发现错误,不允许入队列,命令不会执行,所以不会导致一致性问题。执行错误:命令执行期间报错的时候,错误的命令不会对数据库进行任何改动,所以不会导致一致性问题。
服务器挂了:没有开启持久化,重启后是个空的数据库,可以达到一个新的一致的状态;开了RDB或者AOF持久化,可以将数据库恢复到一个一致性的状态。
隔离性:redis服务器总是单线程执行事务并且不会被中断,即事务总是串行执行的,A事务执行完才会执行B事务,所以没有隔离性的问题。
持久性:redis的事务只是简单的将一堆redis命令打包到一个队列里面,没有任何额外的持久化保证,所以redis事务的持久化要依赖redis使用的持久化机制。
未开启持久化:redis没法进行持久化,不能保证持久性
RDB模式: RDB模式要在某种触发条件下才会进行持久化操作,所以没法保证持久化。
AOF模式:需要看
appendfsync
参数具体的值,如果是alway 则每次执行命令都会进行持久化操作,那么可以保证持久化,在everysec
和no
的情况下没法保证持久化。
黑魔法: 事务里面最后一句加个save
命令可以保证持久性,但是效率比较低下
总结
redis支持事务,在一定的配置下满足事务的ACID四个特性,但是又和传统关系性数据库的事务有所区别。