面试题答案
一键面试1. 使用事务(MULTI - EXEC)
- 原理:在事务中,使用
MULTI
开启事务,之后的命令会被放入队列暂存,并不会立即执行。直到执行EXEC
时,队列中的所有命令才会按顺序原子性地执行。这保证了事务内的命令要么全部成功执行,要么全部不执行。 - 适用场景:适用于需要保证一组命令的原子性执行,例如在一个操作中需要对多个键进行读写操作,确保在这组操作执行过程中,数据状态不会被其他并发操作干扰。比如在一个转账操作中,从账户A扣钱和向账户B加钱这两个操作需要原子性完成。
2. 使用乐观锁(WATCH 命令)
- 原理:通过
WATCH
命令监控一个或多个键。在执行事务前,若被监控的键没有被其他客户端修改,事务可以正常执行;若被监控的键在EXEC
执行前被修改,事务会执行失败,返回nil
。客户端可以根据返回值决定是否重新执行事务。 - 适用场景:适用于读多写少的场景,因为不需要在整个操作过程中对数据加锁,性能较高。例如在一个商品库存的更新场景中,先读取库存,在业务逻辑处理后尝试更新库存,使用乐观锁可以确保在读取库存到更新库存期间,库存没有被其他客户端修改。
3. 使用 SETNX 命令实现分布式锁
- 原理:
SETNX key value
命令,当且仅当键key
不存在时,将键key
的值设置为value
并返回1
,若键key
已存在则不做任何操作并返回0
。客户端尝试获取锁时,若返回1
则获取锁成功,可执行后续操作;获取锁失败则等待或重试。操作完成后通过删除键来释放锁。 - 适用场景:适用于分布式环境下,多个客户端需要对共享资源进行互斥访问的场景。例如多个服务器节点需要竞争访问一个共享资源,通过分布式锁来保证同一时间只有一个节点能操作该资源。
4. 基于 Lua 脚本
- 原理:Redis 执行 Lua 脚本是原子性的,因为 Lua 脚本在执行过程中不会被其他命令打断。可以将多个需要并发控制的命令编写在一个 Lua 脚本中,通过
EVAL
或EVALSHA
命令执行脚本,从而保证这些命令的原子性执行。 - 适用场景:适用于需要对复杂逻辑进行并发控制的场景,将复杂的业务逻辑封装在 Lua 脚本中,保证整个逻辑的原子性。例如在电商的秒杀活动中,包含库存检查、扣减库存、记录订单等一系列复杂操作,可以通过 Lua 脚本保证这些操作在并发环境下的正确性。