什么是事务

事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。它有4个特性:

  • 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行[3]
  • 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束[3]
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行[3]
  • 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中[3]

Redis的事务

Redis如何开启事务

redis开启事务主要有如下4个命令:MULTIEXECDISCARDWATCH

命令 作用
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 则每次执行命令都会进行持久化操作,那么可以保证持久化,在everysecno的情况下没法保证持久化。

​ 黑魔法: 事务里面最后一句加个save命令可以保证持久性,但是效率比较低下

总结

redis支持事务,在一定的配置下满足事务的ACID四个特性,但是又和传统关系性数据库的事务有所区别。