事务相关命令:
MULTI:开启事务
EXEC:执行事务
DISCARD:取消事务,事务中的语句全部不执行
WATCH:监视某些键,CAS实现乐观锁
WATCH 命令的实现
WATCH 命令是一个乐观锁,它可以在 EXEC 命令执行之前,监视任意数量的数据库键,并在 EXEC 命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话,服务器拒绝执行事务,并向客户端返回代表事务执行失败的空恢复。
例:
如果监视的数据在事务中没有使用,但是被修改了,依然会执行失败
WATCH具体实现:
每个 Redis 数据库都保存着一个 watched_keys 字典,这个字典的键是某个被 WATCH 命令监视的数据库键,而字典的值则是一个链表,链表中记录了所有监视相应数据库键的客户端。
所有对数据库进行修改的命令,在执行后都会调用 multi.c/touchWatchKey 函数对 watched_keys 字典进行检查,查看是否有客户端正在监视刚刚被命令修改过的数据库键,如果有的话,那么 touchWatchKey 函数会将监视被修改键的客户端的 REDIS_DIRTY_CAS 标识打开,表示该客户端的事务安全性以及被破坏。
当服务器接收到客户端发来的 EXEC 命令的时候,服务器会根据客户端是否打开了 REDIS_DIRTY_CAS 标识来决定是否执行事务。如果打开了,则服务器拒绝客户端事务的提交,如果没打开,则事务正常执行。
事务的 ACID 性质
1.原子性
事务具有原子性指的是,数据库将事务中的多个操作当作一个整体来执行,服务器要么就执行事务中的所有操作,要么就一个操作也不执行。Redis 的事务是具有原子性的。
发生语法错误,事务中的所有命令都不执行,保证了原子性。
Redis 的事务并不支持回滚,即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直到将事务队列中的所有命令执行完毕为止。虽然第二个语句是 error 但是事务中的所有语句都执行了,保证了原子性。
2.一致性
事务具有一致性指的是,如果数据库在执行事务前是一致的,那么在事务执行之后,无论事务是否执行成功,数据库也任然应该是一致的。
Redis 的事务具有一致性(只要保证事务的原子性和隔离性就能保证事务的一致性)
3.隔离性
事务的隔离性是指,即使数据库中有多个事务并发的执行,各个事务之间也不会相互影响,并且在并发状态下执行的事务和串行执行的事务产生的结果完全相同。
因为 Redis 使用单线程的方式来执行事务,并且服务器保证在执行事务期间不会对事务进行中断,所以 Redis 的事务是具有隔离性的。
4.持久性
事务的持久性指的是,当一个事务执行完毕时,执行这个事务所得的结果以及被保存到永久性存储介质(比如硬盘)里面了,即使服务器在事务执行完毕之后停机,执行事务所得的结果也不会丢失。
Redis 在不同的持久化模式下,持久性不一样:
- RDB 持久化模式,Redis 事务不具有持久性
- AOF 持久化模式,appendfsync 选项的值为 ererysec 或 no 时,Redis 事务不具有持久性;appendfsync 选项的值为 always 时,Redis 事务具有持久性。