Redis乐观锁详解

一、乐观锁概述

乐观锁是一种并发控制机制,它假定在数据变更时不会有冲突发生,因此不会像悲观锁一样在操作时先加锁。

在Redis中,乐观锁常用于多线程、多用户同时操作同一个数据的场景,例如秒杀、抢购、投票等。

二、Redis实现乐观锁的常用方法

1. WATCH/MULTI/EXEC

Redis通过 WATCH/MULTI/EXEC 指令实现乐观锁。这种方式基于事务,所以必须使用 Redis 2.0.0 版本以上才能使用。它的具体实现步骤如下:

// PHP代码示例
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$key = 'goods_1001';
$quantity = 10;

$redis->watch($key); // 监听商品库存
$currentQuantity = $redis->get($key);
if ($currentQuantity unwatch(); // 取消监听
    echo '库存不足';
} else {
    $redis->multi(); // 开启事务
    $redis->decrby($key, $quantity); // 减少商品库存
    $redis->exec(); // 提交事务
    echo '扣减成功';
}

2. Redis分布式锁

分布式锁基于SETNX(SET if Not eXists)指令实现。使用 SETNX 可以在Redis中创建一个不存在的Key,如果该Key已存在,则设置失败,返回0,设置成功返回1。

在使用Redis分布式锁时,应该注意以下问题:

(1)由于每个客户端都是独立的,所以在执行一个操作时可能会有多个客户端同时重复执行。我们需要解决相互之间的干扰。

(2)如果Redis分布式锁的Key在SETNX后会因某种原因过期,那么仍然存在多个进程同时竞争锁的情况。

// PHP代码示例
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$key = 'lock_key';
$value = uniqid(); // 生成唯一值作为锁的值
$expire = 10; // 锁过期时间,单位为秒

if ($redis->setnx($key, $value)) { // SETNX创建Key
    $redis->expire($key, $expire); // 设置Key过期时间
    echo '加锁成功';
    // TODO:执行业务逻辑
    $redis->del($key); // 释放锁
} else {
    echo '加锁失败';
}

三、实战应用:Redis实现秒杀系统

下面结合Redis实现秒杀系统,以更形象地认识乐观锁。

假设有100个商品,每个用户最多能够购买3个,当库存不足时不允许继续购买。

系统的实现思路如下:

(1)使用 Redis 分布式锁保证操作的同步。

(2)在 Redis 中存储每个用户的购买次数。

(3)通过 Redis 事务,先锁定 Redis 中的库存和用户购买次数,再判断库存和用户购买次数是否充足,若充足扣减库存和购买次数。

// PHP代码示例
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$key = 'goods_1001';
$quantity = 10;

$user_id = 101;
$user_key = "user_{$user_id}";
$user_limit = 3;

$lock_key = 'lock_key';
$lock_expire = 10;

// 获取分布式锁
while (!$redis->setnx($lock_key, uniqid())) {
    usleep(1000); // 暂停1ms再次尝试
}
$redis->expire($lock_key, $lock_expire);

// 判断商品库存是否充足
$redis->watch($key, $user_key);
$currentQuantity = $redis->get($key);
$currentUserLimit = $redis->get($user_key) ?? 0;
if ($currentQuantity >= $quantity && $currentUserLimit multi();
    $redis->incrby($user_key, 1); // 记录用户购买次数+1
    $redis->decrby($key, $quantity); // 商品库存-10
    // 执行Redis事务
    $res = $redis->exec();
    if ($res) {
        echo '购买成功';
    } else {
        echo '购买失败';
    }
} else {
    echo '购买失败,库存不足或购买次数已达上限';
}
$redis->del($lock_key); // 释放分布式锁

总结

本文详细介绍了Redis乐观锁的实现方式,其中包括使用 Redis 事务和 Redis 分布式锁两种方式。在实际应用中,需要根据具体业务场景选择合适的方式来实现乐观锁。希望能对读者有所帮助。

原创文章,作者:ASBQA,如若转载,请注明出处:https://www.506064.com/n/372658.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
ASBQAASBQA
上一篇 2025-04-24 06:40
下一篇 2025-04-25 15:26

相关推荐

  • 在CentOS上安装Redis

    Redis是一款非关系型数据库,它支持多种数据结构,包括字符串、哈希、列表、集合、有序集合等。Redis运行内存内并且支持数据持久化,它还可以应用于缓存、消息队列等场景。本文将介绍…

    编程 2025-04-28
  • 解析spring.redis.cluster.max-redirects参数

    本文将围绕spring.redis.cluster.max-redirects参数进行详细阐述,从多个方面解读它的意义与作用,并给出相应的代码示例。 一、基础概念 在介绍sprin…

    编程 2025-04-27
  • Redis Bitmap用法介绍

    Redis是一款高性能的内存数据库,支持多种数据类型,其中之一便是bitmap。Redis bitmap(位图)是一种用二进制位来表示元素是否在集合中的数据结构。由于使用了二进制位…

    编程 2025-04-27
  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • nginx与apache应用开发详解

    一、概述 nginx和apache都是常见的web服务器。nginx是一个高性能的反向代理web服务器,将负载均衡和缓存集成在了一起,可以动静分离。apache是一个可扩展的web…

    编程 2025-04-25
  • 详解eclipse设置

    一、安装与基础设置 1、下载eclipse并进行安装。 2、打开eclipse,选择对应的工作空间路径。 File -> Switch Workspace -> [选择…

    编程 2025-04-25
  • Python输入输出详解

    一、文件读写 Python中文件的读写操作是必不可少的基本技能之一。读写文件分别使用open()函数中的’r’和’w’参数,读取文件…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25
  • git config user.name的详解

    一、为什么要使用git config user.name? git是一个非常流行的分布式版本控制系统,很多程序员都会用到它。在使用git commit提交代码时,需要记录commi…

    编程 2025-04-25

发表回复

登录后才能评论