【工具类】RedisUtil 操作相关

news2025/1/7 23:59:21

目标

一行代码调用

安装

redis

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

hutool 工具类

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.16</version>
        </dependency>

配置

spring:
  data:
    redis:
      host: xxx
      port: 6379
      password: xxx
      database: x

配置类

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * 方便获取 Spring IOC 实例
 *
 * @author jason
 */
@Configuration
@Import(cn.hutool.extra.spring.SpringUtil.class)
public class BeanConf {
}

工具类

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

/**
 * Redis 操作工具类
 *
 * @author jason
 */
@Slf4j
@Component
public class RedisUtil {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public static RedisUtil instance() {
        return SpringUtil.getBean(RedisUtil.class);
    }

    /**
     * set
     */
    public static void set(String key, Object value) {
        instance().stringRedisTemplate.opsForValue().set(key, StrUtil.toStringOrNull(value));
    }

    /**
     * get
     */
    public static String get(String key) {
        return instance().stringRedisTemplate.opsForValue().get(key);
    }

    /**
     * decr 扣减
     */
    public static Long decrement(String key) {
        return instance().stringRedisTemplate.opsForValue().decrement(key);
    }

    /**
     * incr 增加
     */
    public static Long increment(String key) {
        return instance().stringRedisTemplate.opsForValue().increment(key);
    }

    /**
     * 无锁:decr 扣减 + incr 回滚
     */
    public static boolean decrementCouponId(String couponId) {
        // 库存 - 1
        Long decrementNum = RedisUtil.decrement(couponId);
        log.info("优惠券扣减后库存:{}", decrementNum);

        // 库存 + 1
        if (decrementNum < 0) {
            Long incrementNum = RedisUtil.increment(couponId);
            log.info("优惠券回滚后库存:{}", incrementNum);
            return false;
        }
        return true;
    }

    /**
     * 无锁:lua + decr 扣减
     */
    public static Boolean luaDecrCid(String couponId) {
        // Lua 脚本
        String script = """
                local couponId = KEYS[1]
                local value = tonumber(redis.call('GET', couponId))

                if value > 0 then
                    redis.call('DECR', couponId)
                    return true
                else
                    return false
                end
                """;
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(script, Boolean.class);
        return instance().stringRedisTemplate.execute(redisScript, CollectionUtil.newArrayList(couponId));
    }

    /**
     * 无锁:lua + decr 扣减
     *
     * 限制:1个用户,1张券
     */
    public static Boolean luaUserCid(String userId, String couponId) {
        // Lua 脚本
        String script = """
                local userId = KEYS[1]
                local couponId = KEYS[2]
                local isUserSuccess = redis.call('GET', userId)
                local value = tonumber(redis.call('GET', couponId))

                if isUserSuccess ~= "true" and value > 0 then
                    redis.call('DECR', couponId)
                    redis.call('SET', userId, "true")
                    return true
                else
                    return false
                end
                """;
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(script, Boolean.class);
        return instance().stringRedisTemplate.execute(redisScript, CollectionUtil.newArrayList(userId, couponId));
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2272270.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

得物基于AIGC生成测试用例的探索与实践

一、背景 随着人工智能技术的快速发展&#xff0c;尤其是在自然语言处理&#xff08;NLP&#xff09;、计算机视觉和生成对抗网络&#xff08;GANs&#xff09;等领域&#xff0c;AIGC&#xff08;AI Generated Content&#xff09;得到了广泛应用&#xff0c;这一技术的进步使…

HTML5实现好看的二十四节气网页源码

HTML5实现好看的新年春节元旦网站源码 前言一、设计来源1.1 主界面1.2 关于我们界面1.3 春季节气界面1.4 夏季节气界面1.5 秋季节气界面1.6 冬季节气界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载结束语 HTML5实现好看的二十四节气网页源码&#xff0c;春季节气&#xf…

Hadoop集群之间实现免密登录

实现虚拟机之间能够互相登录&#xff0c;比如可以在hadoop1上面登录hadoop2。 第一步&#xff1a;执行”ssh-keygen -t rsa”命令&#xff0c;生成该虚拟机的密钥 第二步&#xff1a;密钥文件存储在/root/.ssh目录&#xff0c;执行cd /root/.ssh命令进入存储密钥文件的目录&am…

国产编辑器EverEdit - 常用资源汇总

1 国产编辑器EverEdit-常用资源汇总 EverEdit是一款国产文本编辑器&#xff0c;历经超过15年的更新和维护&#xff0c;拥有不输业界顶级商业文本编辑器(EmEditor、UltraEdit)的实力&#xff0c;甚至在某些方面的功能更强(当然&#xff0c;各有千秋)&#xff0c;开发者对文本编辑…

C# 枚举格式字符串

总目录 前言 当前文章为 C# 中的格式设置(格式化字符串) 大全 中的一个小章节。 一、概述 1. 基本信息 可以使用 Enum.ToString 方法&#xff0c;新建表示枚举成员的数字值、十六进制值或字符串值的字符串对象。枚举格式说明符不区分大小写。 二、自定义数字格式说明符详解…

SQL-Server链接服务器访问Oracle数据

SQL Server 链接服务器访问 Oracle 离线安装 .NET Framework 3.5 方法一&#xff1a;使用 NetFx3.cab 文件 下载 NetFx3.cab 文件&#xff0c;并将其放置在 Windows 10 系统盘的 C:Windows 文件夹中。 以管理员身份运行命令提示符&#xff0c;输入以下命令并回车&#xff1a; …

Microi吾码|开源低代码.NET、VUE低代码项目,表单引擎介绍

Microi吾码&#xff5c;开源低代码.NET、VUE低代码项目&#xff0c;表单引擎介绍 一、摘要二、Microi吾码介绍2.1 功能介绍2.2 团队介绍2.3 上线项目案例 三、Microi吾码表单引擎是什么&#xff1f;四、Microi吾码表单引擎功能4.1 模块引擎 - 由表单引擎驱动4.2 流程引擎 - 由表…

自动化立体库安全使用管理制度完整版

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。欢迎大家到本文底部评论区留言。 新书《智能物流系统构成与技术实践》人俱乐部 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载。 以下是《…

ArcGIS中怎么把数据提取到指定范围(裁剪、掩膜提取)

最近&#xff0c;经常能收到怎么把数据提取到指定范围、栅格数据怎么裁剪、矢量数据怎么裁剪、栅格数据怎么掩膜提取的咨询。 下面是我对这个问题的解决思路&#xff1a; 对于矢量数据&#xff1a; ①首先把数据加载进来 ②软件界面上面的工具栏找到→地理处理→裁剪&#x…

stm32的掉电检测机制——PVD

有时在一些应用中&#xff0c;我们需要检测系统是否掉电了&#xff0c;或者要在掉电的瞬间需要做一些处理。 STM32内部自带PVD功能&#xff0c;用于对MCU供电电压VDD进行监控。 STM32就有这样的掉电检测机制——PVD(Programmable Voltage Detecter)&#xff0c;即可编程电压检…

QT:控件属性及常用控件(2)-----按钮类控件及显示类控件

文章目录 QT关于qrc一个蛋疼的问题一、按钮类控件1.PushButton1.1 给按钮加图标1.2 给按钮加快捷键 2.RadioButtion2.1 单选题2.2 关于状态2.3 多组单选 3.Check Box4.Tool Button 二、显示类控件1.Lable1.1 文本、图片显示1.2 Label格式1.3 设置伙伴(绑定伙伴关系) 2.LCDNumbe…

逆向入门(2)C篇-基础知识

C基础 1、在C中&#xff0c;函数的变量是从右往左传递的&#xff0c;也就是test(x,y)&#xff0c;先传入y&#xff0c;再传x。 2、变量的分类&#xff1a; &#xff08;1&#xff09;全局变量。在编译的时候就已经确定了内存地址和宽度&#xff0c;变量名就是内存地址的别名…

【C语言】_assert断言

目录 1. assert功能 2. 使用assert判指针有效性 3. assert的参数 4. NDEBUG宏与assert机制的关闭 5. Debug版本与Release版本 1. assert功能 assert ( ) 是assert.h头文件定义的宏&#xff0c;用于在运行时确保程序符合指定条件&#xff1a; 如果不符合&#xff08;条件…

在Unity中用Ab包加载资源(简单好抄)

第一步创建一个Editor文件夹 第二步编写BuildAb&#xff08;这个脚本一点要放在Editor中因为这是一个编辑器脚本&#xff0c;放在其他地方可能会报错&#xff09; using System.IO; using UnityEditor; using UnityEngine;public class BuildAb : MonoBehaviour {// 在Unity编…

【可实战】Bug的判定标准、分类、优先级、定位方法、提交Bug(包含常见面试题)

一、Bug相关概念 &#xff08;一&#xff09;bug判定标准 &#xff08;二&#xff09;常见 Bug 分类 &#xff08;三&#xff09;bug优先级 1.bug严重程度与优先级的关系 有些很严重的Bug&#xff0c;只在极端的条件下才出现&#xff0c;用户碰到的概率很低&#xff0c;这种情…

C语言:调试的概念和调试器的选择

所谓调试&#xff08;Dubug&#xff09;&#xff0c;就是跟踪程序的运行过程&#xff0c;从而发现程序的逻辑错误&#xff08;思路错误&#xff09;&#xff0c;或者隐藏的缺陷&#xff08;Bug&#xff09;。 在调试的过程中&#xff0c;我们可以监控程序的每一个细节&#xff…

30分钟搭建 Typecho 个人博客教程

Typecho是一款PHP博客程序&#xff0c;相比于WordPress&#xff0c;Typecho显得更加的轻量级和简洁。现在越来越多的人倾向于用Typecho来搭建个人博客——众所周知&#xff0c;能跑WordPress的机器都不便宜。 Typecho是一款国人团结打造的开源博客系统&#xff0c;和WordPress…

【软考网工笔记】计算机基础理论与安全——网络安全

病毒 Melissa 宏病毒 1. 是一种快速传播的能够感染那些使用MS Word 97 和MS Office 2000 的计算机宏病毒。 2. 前面有**Macro** 表示这是宏病毒&#xff1b; 3. 宏病毒可以感染后缀为.xls的文件&#xff1b;Worm 蠕虫病毒 1. 通常是通过网络或者系统漏洞进行传播。 2. 利用信…

数字图像处理 三 空间滤波

空间滤波是一种图像处理技术&#xff0c;它通过对图像像素及其邻域进行运算&#xff0c;利用均值&#xff0c;高斯&#xff0c;梯度&#xff0c;拉普拉斯等线性滤波和中值&#xff0c;最大最小&#xff0c;双边滤波等非线性滤波改变像素值&#xff0c;实现图像的平滑&#xff0…

记录一次电脑被入侵用来挖矿的过程(Trojan、Miner、Hack、turminoob)

文章目录 0、总结1、背景2、端倪3、有个微软的系统更新&#xff0c;就想着更新看看&#xff08;能否冲掉问题&#xff09;4、更新没成功&#xff0c;自动重启电脑5、风险文件&#xff08;好家伙命名还挺规范&#xff0c;一看名字就知道出问题了&#xff09;6、开机有一些注册表…