本文介绍Redis中的事务。和MySQL中一样,事务是为了保证一组数据操作放在一起执行,来保证这些操作能够统一执行成功或者统一执行失败。Redis本质上是为了提升效率,所以其对事务的处理并没有MySQL那么全面。
1. 事务概述
Redis的事务:允许把一组Redis命令放在一起执行,把命令进行序列化,然后一起执行。保证部分原子性。如果命令都执行成功,那么就保证了原子性。如果其中有命令出现了严重错误,那么全部操作则回退,保证了原子性。如果出现了一般错误,那么仅该条命令不执行,其余命令正常执行,没有保证原子性。
2. 命令
2.1 事务的开启与关闭
- multi:标记一个事务的开始。
- exec:标记事务的结束,并执行事务队列中的所有命令。
本质上,在输入multi命令后,后续输入的命令在输入后不会立即执行,而是被压入到事务队列中。待输入exec命令后,这些输入的命令才会开始依次执行。
如果命令在压入事务队列过程中发生了错误,这些错误就被认为是严重错误,即本事务队列中所有命令都不会执行。如下所示:
如果一组命令中,在压入队列过程中正常,但是在执行命令时发生了错误,则只会影响发生错误的命令,不会影响其他命令的执行,此时不能保证事务的原子性。如下所示:
个人感觉,这里有点像编译时错误和运行时错误,即Redis如果检测除了编译时错误,就不会执行命令(保证原子性)。如果是运行时错误,则会执行剩余的命令(不会保证原子性)。
2.2 discard命令
清除命令,放弃已经压入事务队列的命令,即不执行事务队列中的命令,将事务结束。
2.3 Redis中的乐观锁
watch key
:监控某一个key,当事务在执行过程中,如果此键的值发生了变化,那么本事务放弃执行。否则正常执行。
因为在乐观锁中,为了防止两个事务对同一条数据进行修改,比如读未提交。此时会新增一个字段,在事务开启的时候读取该字段并保留其值,在事务提交的时候会再次读该字段(在执行命令的时候会更新该字段),判断两次读取的字段值是否一样。如果一样,那么就说明别人没有修改,此时本事务可以正常执行。如果不一样,则说明本次已经读取的数据已经无效了,因为其他人已经修改了该数据。
在Redis中,这个watch命令就是用于监控某个key,在事务的开启和结束(执行命令)的时候分别读取该key值,判断是否一样。
但是Redis只是提供了这种机制,在实际开发中,为了追求效率,乐观锁基本上不怎么用。
unwatch
:放弃已经监控的所有的键。
3. 小节
Redis事务有以下特点:
- 单独的隔离操作:事务中的所有命令都会序列化、顺序地执行。事务在执行过程中,不会被其他客户端发来的命令请求所打断。除非使用了watch命令监控key,即乐观锁。
- 不保证事务的原子性:Redis同一个事务中如果一条命令执行失败,其后的命令仍然可能会被执行。Redis的事务没有回滚。Redis已经在系统内部进行功能简化,这样可以确保更快的运行速度。因为Redis不需要事务回滚的能力。
4. 备注
参考B站《动力节点》。