字节一面:了解Redis的事务吗?它的命令有哪些?它和MySQL的事务有什么区别?
MySQL 事务
mysql的事务主要要4个特点,也就是ACID,这是面试常问到的点
Atomicity(原子性):事务中的操作要么全部执行,要么全部不执行
Consistency(一致性):事务执行前后,数据库中数据在逻辑上都是正确的。常举的例子是,A给B转100块,执行前A的账户有a元,B的账户有b元,执行后A的账户是a-100, b的账户 b+100,这就是一致性。
Isolation(独立性):数据库中的事务的执行是相互不干扰的
Durability(持久性):事务执行完后,结果是永久生效的,就算断电后重启也是生效的
Redis事务
Redis官方文档对事务的描述如下图所示

总结:Redis的事务指的是使用核心命令,例如 MULTI, EXEC,DSICARD, WATCH,让一组命令在一个单步中顺序执行。
让我们来一个一个看每个命令的作用
MULTI

官方文档的描述是:MULTI标记了一组命令的开始,它标记了一个事务的执行入口,这组命令按照加入的顺序进行排放,使用了MULTI命令后,后续的命令不会被执行,直到执行EXEC命令时,这组命令就会按照顺序执行

可以看出,当我们输入MULTI时,后续输入的命令不会被立刻执行,而是放进了队列里,成功将命令放进队列时会返回 QUEUED 字符串标志
EXEC
)
官方文档描述:调用EXEC命令时,Redis会按照顺序执行MULTI之后入队的所有命令。
如果使用了WATCH命令,相当于实现一个【乐观锁】,监控一个或多个键值的变化。这些键值没有被改变才能执行事务,否则不执行事务

WATCH

官方文档描述:调用 WATCH 命令监听多个键值的变化,作为判断能否执行事务的条件。如果在执行事务前或期间监听的键值对发生变化,那么放弃执行事务


UNWATCH

官方文档描述:清空当前连接中所有被 WATCH 监听的键,取消对这些键的乐观锁监控。

DISCARD

官方文档描述:
- 清空事务队列
取消当前连接中所有通过MULTI入队的命令,使连接退出事务状态,恢复正常执行模式。 - 自动释放
WATCH监听
如果事务开始前调用了WATCH,DISCARD会自动清除所有被监听的键(效果等同于UNWATCH)

MULTI创建一个队列,输入一组命令,然后输入 DISCARD, 当执行 EXEC 时,返回错误提示信息:没有可执行的事务。
除了Redis这些特有的命令,Redis的事务的最大特点是什么?
Redis如何处理事务执行过程中发生的错误
还是来看一下官方文档

官方文档表述:在执行一个事务的时候,可能会在两个地方发生错误
第一处:调用MULTI命令时, 命令入队列错误(可能因为语法、参数等错误)。
redis 2.6.5之前的版本和之后的版本,对于第一处错误有不同的处理方式,2.6.5之后的版本会对入队列的命令进行一个检测,如果检测到有错误,会拒绝执行事务,调用EXEC命令时返回错误。
redis2.6.5之前的版本,在入队列时检测错误,如果有错误,由客户端决定是否是继续执行事务还是放弃事务
第二处:执行EXEC时命令执行错误
redis的特点是,队列中的命令执行失败了,并不会影响它后面命令的执行,这和MySql有很大的区别
Redis有回滚吗?为什么?

官方文档解释:Redis是不支持回滚操作的,这是为了保证Redis的简单性和高性能。

尝试一下创建一个事务,这个事务包含4条命令,第三条命令是错误的,他们都成功入队列了,当执行EXEC时,可以发现,第三条命令失败了,但是第四条命令可以执行成功。验证了redis事务中的命令执行失败并不会影响其它命令的执行。
得出结论: redis的事务不保证命令全部执行正确,它只保证一系列命令执行的原子性。
我们来分析一下,为什么redis不支持回滚操作?
redis 的设计思想:简单、高效!事务回滚是复杂的,违背设计原则
redis 的问题设计初衷是简单高效,事务回滚会增加复杂性
redis 的单线程模型让命令执行是串行的,天然不需要处理多线程并发带来的事务回滚操作
事务中的错误通常是语法错误,应该在开发阶段解决,而不是在运行时回滚
事务回滚必然要维护旧的数据状态,但是redis 是简单高效的缓存,不是强一致性的数据库
redis 是内存数据库,选择牺牲回滚能力换取更高的吞吐能力