Redis事务1. 什么是 Redis 事务Redis 事务允许一次性执行多个命令这些命令会按顺序串行化执行在执行过程中不会被其他客户端的命令打断。生活场景比喻传统数据库事务像银行转账 - 要么全部成功A扣款B收款 - 要么全部失败都不执行 Redis 事务像购物清单 - 把要买的东西列出来然后一次性结账 - 但结账时如果某件商品有问题只跳过那件商品其他照常购买2. Redis 事务的核心命令命令作用关键点MULTI开启事务之后的命令不会立即执行而是加入队列EXEC执行事务一次性执行队列里所有命令结束事务DISCARD放弃事务清空队列所有命令都不执行WATCH监控 Key监控的 key 被修改事务自动失败实现乐观锁UNWATCH取消监控取消对所有 key 的监控3. 基本事务使用简单事务示例# 开启事务 127.0.0.1:6379 MULTI OK # 将多个命令加入队列 127.0.0.1:6379 SET user:1001:name 张三 QUEUED 127.0.0.1:6379 SET user:1001:age 25 QUEUED 127.0.0.1:6379 INCR user:id_counter QUEUED # 执行事务 127.0.0.1:6379 EXEC 1) OK 2) OK 3) (integer) 101事务执行流程MULTI → 开始事务 命令1 → 命令入队返回 QUEUED 命令2 → 命令入队返回 QUEUED 命令3 → 命令入队返回 QUEUED EXEC → 按顺序执行所有命令返回结果数组4. 事务中的错误处理Redis 事务有两种错误情况4.1 入队时错误语法错误127.0.0.1:6379 MULTI OK 127.0.0.1:6379 SET key1 value1 QUEUED 127.0.0.1:6379 SET key2 # 语法错误缺少value (error) ERR wrong number of arguments for set command 127.0.0.1:6379 SET key3 value3 QUEUED 127.0.0.1:6379 EXEC (error) EXECABORT Transaction discarded because of previous errors. # 整个事务都不会执行4.2 执行时错误运行时错误127.0.0.1:6379 MULTI OK 127.0.0.1:6379 SET key1 value1 QUEUED 127.0.0.1:6379 INCR key1 # key1的值不是数字执行时会出错 QUEUED 127.0.0.1:6379 SET key2 value2 QUEUED 127.0.0.1:6379 EXEC 1) OK # SET key1 成功 2) (error) ERR value is not an integer or out of range # INCR 失败 3) OK # SET key2 成功继续执行重要特点Redis 事务在执行时遇到错误不会回滚会继续执行后续命令Redis 事务 vs 数据库事务对比项Redis 事务MySQL 数据库事务遵循标准不严格遵循 ACID完全遵循 ACID 四大特性原子性不满足语法错全不执行运行错部分成功无回滚完全满足要么全部成功失败全部回滚一致性弱一致性强事务一致性隔离性串行执行简单隔离支持 4 种隔离级别读未提交串行化持久性依赖 RDB/AOF 持久化事务本身不保证提交后立刻落盘强持久回滚机制无事务回滚支持ROLLBACK手动回滚异常处理出错继续往下执行出错直接整体回使用场景简单批量命令、缓存操作金融、订单、支付等高一致性业务实现方式命令队列排队执行事务日志 锁机制5. WATCH 命令 - 乐观锁什么是乐观锁在事务执行前监视一个或多个键如果在事务执行期间这些键被其他客户端修改则事务执行失败。使用示例# 客户端1 127.0.0.1:6379 SET balance 100 OK 127.0.0.1:6379 WATCH balance # 开始监视balance OK 127.0.0.1:6379 MULTI OK 127.0.0.1:6379 INCRBY balance 50 QUEUED # 此时客户端2修改了balance # 客户端2127.0.0.1:6379 SET balance 200 # 客户端1继续执行 127.0.0.1:6379 EXEC (nil) # 返回nil表示事务执行失败因为balance被修改了完整的乐观锁模式# 使用循环实现重试机制 while true; do WATCH balance current_balance GET balance MULTI SET balance (current_balance - 10) result EXEC if result ! nil break # 成功执行 end # 失败重试 endredis的持久化Redis是内存数据库如果不将内存中的数据库状态保存到磁盘中那么一旦服务器进程退出服务器中的数据库状态也会消失。所以Redis提供了持久化的功能。1.RDB在指定的时间间隔内将内存中的数据集快照写入磁盘也就是Snapshot快照它恢复时是将快照文件直接读到内存中。Redis会单独创建fork一个子进程来进程持久化会先将数据写入到一个临时文件中待持久化过程都结束了再用这个临时文件替换上一次持久化好的文件。整个过程中主进程是不进行任何IO操作的这就确保了极高的性能。如果需要进程大规模数据的恢复且对数据恢复的完整性不是非常敏感那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失rdb保存的文件是dump.rdb触发机制1.save的规则满足的情况下会自动触发rdb操作2.执行flushall命令会触发rdb操作3.对出redis时也会触发rdb操作4.备份会自动生成也给dump.rdb文件如何恢复rdb文件只需要将rdb文件放在redis的启动目录下就可以。redis启动时会自动检查dump.rdb文件恢复其中的数据优点适合大规模的数据恢复对数据的完整性要求不高缺点需要一定的时间间隔进行操作如果redis意外宕机最后一次持久化后的操作数据就没有了fork进程的时候会需要占用一定的内存空间2.AOF将所有写操作的命令都记录下来类似history恢复时将所有的命令都执行一遍AOF保存的文件是appendonly.aof如果这个aof文件被恶意修改这个时候redis是启动不起来的我们需要修复这个aof文件redis提供的一个工具 redis-check-aof --fix 来修改aof文件优点1. 每一次修改都同步文件的完整性比较好2.每秒同步一次可能会丢失1s的数据缺点1. 相对于数据文件来说aof远远大于rdb2.修复的速度比rdb慢3.AOF的运行效率也比rdb慢