事务的概念及用法
- 什么是事务
- 事务的操作
- 开启事务(MULTI)
- 执行事务(EXEC)
- 中止事务(DISCARD)
- 为事务提供检查(WATCH)
- 取消对key的监控(UNWATCH)
- 为什么Redis不支持回滚 ?
- 事务中的错误
- Redis脚本
- 总结
什么是事务
Redis的事务和MSOL的事务概念上是类似的.都是把一系列操作绑定成一组.让这一组能够批量执行
但是注意体会Redis的事务和MySQL事务的区别
- 弱化的原子性:redis没有“回滚机制”只能做到这些操作批量执行”不能做到一个失败就恢复到初始状态
- 不保证一致性:不涉及“约束”也没有回滚.MySQL的一致性体现的是运行事务前和运行后,结果都是合理有效的,不会出现中间非法状态
- 不需要隔离性:也没有隔离级别,因为不会并发执行事务(redis单线程处理请求)
- 不需要持久性:是保存在内存的.是否开启持久化,是redis-server自己的事情,和事务无关
Redis事务本质上是在服务器上搞了一个事务队列,每次客户端在事务中进行一个操作,都会把命令先发给服务器,放到”事务队列”中(但是并不会立即执行
而是会在真正收到EXEC命令之后,才真正执行队列中的所有操作
因此,Redis的事务的功能相比于MySQL来说,是弱化很多的.只能保证事务中的这几个操作是“连续的”不会被别的客户端加塞”仅此而已
事务的操作
开启事务(MULTI)
MULTI开启事务,执行成功后返回OK
127.0.0.1:6379> MULTI
OK
执行事务(EXEC)
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> incr k2
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 1
2) (integer) 1
中止事务(DISCARD)
DISCARD可用于放弃当前的事务,丢弃命令队列,不执行任何命令,并且连接的状态恢复正常
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> incr k2
QUEUED
127.0.0.1:6379> DISCARD
OK
为事务提供检查(WATCH)
WATCH能够有效解决在并发情况下,可能出现的数据不一致的情况
WATCH在该客户端上监控一组具体的key
当开启事务的时候,如果对WATCH的key进行修改,就会记录当前key的“版本号(版本号是个简单的整数,每次修改都会使版本变大.服务器来维护每个key的版本号情况
在真正提交事务的时候,如果发现当前服务器上的key的版本号已经超过了事务开始时的版本号,就会让事务执行失败.(事务中的所有操作都不执行)
注意:在Redis版本6.0.9之前, 已过期的键不会导致事务中止。
事务内的命令不会触发WATCH条件,因为它们只排队,直到发送EXEC
WATCH可以多次调用。所有WATCH调用将具有从调用开始监视更改的效果,直到调用EXEC。您还可以将任意数量的键发送到单个WATCH调用中。
可以看到当有另外的客户端对我们进行了WATCH操作的key进行修改的时候,事务就失效了
取消对key的监控(UNWATCH)
相当于WATCH的逆操作
为什么Redis不支持回滚 ?
Redis在事务失败时不支持回滚,而是继续执行余下的命令。
Redis命令只因为语法的错误而失败,或者命令用在了错误类型的键上面。也就是说,失败的命令是由编程错误造成的,而这些错误在开发过程中被发现,而不应该出现在生产环境中。
因为不需要对回滚进行支持,所以Redis的内部可以保持简单且快速。
事务中的错误
在事务中,可能会遇到两种类型的命令错误
- 命令可能无法排队,因此在调用EXEC之前可能会发生错误。例如,命令在语法上可能是错误的(参数数量错误、命令名称错误等),或者可能存在某些关键条件,如内存不足条件(如果服务器使用maxmemory指令配置了内存限制)。
- 命令可能在调用EXEC后失败,例如因为我们针对具有错误值的键执行了操作(例如,针对字符串值执行列表操作)。
从Redis2.6.5版本开始,服务器将检测在积累命令期间发生的错误。然后,它将拒绝执行事务,返回在EXEC期间的错误,并放弃该事务。
对于Redis版本 < 2.6.5:在Redis2.6.5之前,客户端需要检测在执行EXEC之前发生的错误,方法是检查排队命令的返回值:如果命令回复为QUEUED,则已正确排队,否则Redis将返回错误。如果在排队命令时发生错误,大多数客户端将中止并放弃事务否则,如果客户端选择继续事务,EXEC命令将执行所有已成功排队的命令,而不考虑之前的错误,发生在执行EXEC之后的错误不会以特殊方式处理:即使在事务过程中某些命令失败,所有其他命令仍将执行
Redis脚本
在Redis中进行事务操作的另一个要考虑的事项是Redis脚本(比如lua),它们是事务性的。您可以使用Redis事务执行的一切都可以使用脚本执行,通常脚本既更简单又更快。
总结
对于Redis来说,它本身支持事务的概念,但它不是传统意义上ACID的事务,同时也没办法保证数据的完整性,但是通过MULTI、EXEC、WATCH这样的机制可以保证应用之间的数据的隔离性,解决线程安全的问题。