一、概述
1.1、Redis事务简介
在 Redis 中,事务是一组命令的有序队列,Redis 使用 MULTI、EXEC、WATCH 和 DISCARD 等命令来实现事务。事务的执行是原子的,要么所有命令都执行成功,要么所有命令都不执行。事务中的命令在 EXEC 执行之前不会被实际执行,而是先进入队列,从而实现了原子性操作。
1.2、Redis事务方案
- Redis事务(Transactions):
- Redis事务允许你将一系列命令作为一个原子操作来执行。你可以使用
MULTI
开始事务,然后添加多个命令,最后使用EXEC
提交事务。 - 事务可以包含多个命令,但如果在事务执行期间发生了错误或数据被修改,所有的操作都会被回滚,不会执行任何改变数据的命令。
- Redis脚本(Scripting):
- Redis脚本是使用Lua语言编写的脚本,可以在Redis服务器上原子性地执行。
- 脚本可以包含多个命令,这些命令将被作为一个整体在服务器上执行,要么全部成功,要么全部失败,保证原子性。
- 脚本在执行时是单线程的,这意味着它们不会被其他命令或脚本中断,这有助于确保原子性和一致性。
- 脚本 vs. 事务:
- 虽然事务和脚本都可以实现一组命令的原子性执行,但在某些情况下,脚本可能更为简单和高效。
- 脚本在执行时不需要将多个命令发送到服务器,而是将整个脚本作为一个单一的操作发送,这可以减少通信开销,提高性能。
- 另外,脚本还可以在执行期间访问参数,使其更加灵活。
对于简单的操作,事务可能足够,但对于更复杂的操作或需要原子性保证的情况,脚本可能是更好的选择。总体而言,Redis脚本提供了更灵活、更高效的方式来执行一系列命令。
二、命令事务实现步骤
使用watch、multi、exec等命令来实现一个简单的转账事务:
step1:设置两个账户的初始余额
# 设置两个账户的初始余额
set account1 100
set account2 50
step2:使用watch命令监视两个账户的余额
WATCH命令用于监视一个或多个键,以实现乐观锁(Optimistic Locking)。通过使用WATCH,你可以指定一组键,如果这些键在事务执行期间被其他客户端修改,事务将被取消。这允许你在执行事务之前检查被监视的键是否发生了变化,从而保证事务的原子性。
# 使用watch命令监视两个账户的余额
watch account1 account2
step3:开启事务并执行事务
# 使用multi命令开启事务
multi
# 在事务中,将account1的余额减少10,将account2的余额增加10
decrby account1 10
incrby account2 10
# 使用exec命令提交事务
exec
step4:事务异常模拟
在multi执行之后exec执行之前,如果再开启一个窗口来操作account1,这时第一个窗口的事务就会执行失败,数据的值不会被改变。
比如在执行multi后,新开一个窗口执行:
窗口2:
set account1 200
然后再回到第一个窗口执行剩下的事务命令,最后就会提示异常:
三、Redis脚本事务
Redis官方提到在Redis中,除了使用传统的事务(通过MULTI、EXEC等命令)外,还可以通过Redis脚本来实现类似事务的操作,而且通常情况下脚本会更简单和更快,这里说的脚本就是我们常使用的Lua脚本。
四、Redis事务特点
Redis的事务有以下特点:
- Redis的事务是乐观锁的,也就是说,如果事务中涉及的键在执行前被其他客户端修改,那么事务会被中断,不会执行任何命令。这是通过WATCH命令来实现的,它可以监视一个或多个键,如果这些键在事务执行前被修改,那么事务会失败。这样可以保证事务的隔离性和一致性。
- Redis的事务是基于队列的,也就是说,当客户端执行MULTI命令后,开始一个事务,之后发送的所有命令都会被放入一个队列中,而不是立即执行。只有当客户端执行EXEC命令时,才会触发事务中的所有命令的执行。如果客户端执行DISCARD命令,那么会取消事务,放弃执行队列中的所有命令。
五、Redis事务应用场景
Redis的事务可以用于一些需要保证数据完整性和一致性的场景,例如:
- 购物车结算:当用户结算购物车时,需要从库存中扣除相应的商品数量,同时更新用户的订单信息。这两个操作需要在一个事务中完成,否则可能会出现库存和订单不一致的情况。可以使用WATCH命令来监视库存的键,如果在事务执行前,库存被其他用户修改,那么事务会失败,提示用户重新结算。
- 秒杀活动:当用户参与秒杀活动时,需要判断商品是否还有剩余,如果有,就扣除一个商品,并生成一个订单。这两个操作也需要在一个事务中完成,否则可能会出现超卖的情况。同样可以使用WATCH命令来监视商品的键,如果在事务执行前,商品被其他用户抢购,那么事务会失败,提示用户秒杀失败。
- 排行榜更新:当用户完成某个任务或者获得某个成就时,需要更新用户的积分,并将用户的排名插入到相应的排行榜中。这两个操作也需要在一个事务中完成,否则可能会出现积分和排名不一致的情况。可以使用WATCH命令来监视用户的积分键,如果在事务执行前,用户的积分被其他操作修改,那么事务会失败,提示用户重新更新。