事务

Redis通过命令Multi、Exec、Watch等命令来实现事务(transaction)功能。事务提供了一种将多个命令请求打包,然后一次性,按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而该去执行其他客户端命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。

事务首先是以MULTI命令开始,接着将多个命令放入事务当中,最后由Exec命令将这个事务提交(commit)给服务器执行。

19.1 事务的实现

由以下三个阶段:

  • 1.事务开始 ——mult
  • 2.命令入队 ——get、set...
  • 3.事务执行 —— exec、discard、watch和multi

每个redis客户端都有自己的事务状态,这个事务状态保存在客户端状态的mstat属性里面。事务队列以先进先出的方式保存入队的命令,较先入队的命令会被放到数组的前面,而较后入队的命令则会被放到数组的后面。

当一个处于事务状态的客户端向服务器发送Exec命令时,这个Exec命令将立即被服务器执行。服务器会遍历这个客户端的事务队列,执行队列中保存的所有命令,最后将执行命令所得的结果全部返回给客户端。

19.2 Watch命令的实现

Watch命令是一个乐观锁,它可以在exec命令执行之前,监视任意数量的数据库键,并在Exec命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果要是的话,服务器将拒绝执行事务,并向客户端返回代表事务执行失败的空回复。

19.3 事务的ACID性质

19.3.1 原子性

redis事务不支持事务回滚机制,及时事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去的,直到将事务队列中的所有命令都执行完毕为止。

不支持回滚是因为这种复杂的功能和redis追求简单高效的设计主旨不相符,并且redis事务的执行时错误通常都是编程错误产生的,这种错误通常只会出现在开发环境中,而很少在实际的生成环境出现。

19.3.2 一致性

redis通过谨慎的错误检测和简单的设计来保证事务的一致性,从以下三个部分讲解:

1.入队错误

入队过程中,出现了命令不存在,或者命令的格式不正确等情况,那么redis将拒绝执行这个事务。

2.执行错误

除了入队时可能发生错误外,事务还可能在执行的过程中发生错误: 关于这种错误有两个需要说明的地方:

  • 执行过程中发生的错误都是一些不能在入队时被服务器发现的错误,这些错误只会在命令实际执行时被触发。
  • 即使在事务的执行过程中发生了错误,服务器也不会中断事务的执行,它会继续执行事务中余下的其他命令,并且已被执行的命令不会被出错的命令影响。

3.服务器停机

如果redis服务器在执行事务的过程中停机,那么根据服务器所使用的持久化模式,可能有以下三种情况:

  • 如果服务器运行在无持久化的内存模式下,那么重启之后的数据库将是空白的,因此数据总是一致的。
  • 如果服务器运行在RDB模式下,那么在事务中途停机不会导致不一致性,因为服务器可以根据现有的RDB文件来恢复数据,从而将数据库还原到一个一致的状态。
  • 如果服务器运行在AOF模式下,那么在事务中途停机不会导致不执行,因为服务器可以根据现有的AOF文件来恢复数据,从而将数据库还原到一个一致的状态。

19.3.3 隔离性

redis使用单线程的方式来执行事务,并且服务器保证,在执行事务期间不会对事务进行终端,因此,redsi的事务总是以串行的方式运行的,并且事务也总是具有隔离性。

19.3.4 持久性

因为redis的事务不过是简单的地使用队列包裹起了一组redis命令,redis并没有为事务提供任何额外的持久化功能,所以redis事务的耐久性由redis所使用的持久化模式决定的; 只有在AOF持久化模式下,并且appendfsync选项的值为always时,程序总会执行命令之后调用同步函数,将命令数据真正地保存到硬盘里面,因此这种配置下的事务是具有持久性。

不过不论在什么模式下运作,在一个事务的最后加上SAVE命令总可以保证事务的持久性。但是效率比较低。

results matching ""

    No results matching ""