关于redis锁的简单实现

ops/2024/12/25 15:16:05/

新建RedisLock类。

public class RedisLock implements Serializable {private static final long serialVersionUID = 3077854413624876404L;private static final Log LOG = LogFactory.get(RedisLock.class);/*** 锁标志对应的key*/private String lockKey;/*** 将key 的值设为value ,当且仅当key 不存在,等效于 SETNX。*/private static final String NX = "NX";/*** seconds — 以秒为单位设置 key 的过期时间,等效于EXPIRE key seconds*/private static final String EX = "EX";/*** 调用set后的返回值*/private static final String OK = "OK";/*** 取锁等待中线程等待时间*/private static final Long WAITING_SECONT = 200L;/*** 默认请求锁的等等时间,分钟*/private static final Integer WAIT_MINUTE = 1;/*** 默认锁的有效时间*/private static final Long EXPIRE = 5L;/*** 设置默认上锁时间单位*/private static final TimeUnit TIME_UNIT = TimeUnit.MINUTES;/*** 解锁的lua脚本*/private static final String UNLOCK_LUA;/*** 锁标记*/private volatile boolean locked = false;static {StringBuilder sb = new StringBuilder();sb.append("if redislock.call(\"get\",KEYS[1]) == ARGV[1] ");sb.append("then ");sb.append("    return redislock.call(\"del\",KEYS[1]) ");sb.append("else ");sb.append("    return 0 ");sb.append("end ");UNLOCK_LUA = sb.toString();}/*** 锁的有效时间(s)*/private Long expire = EXPIRE;/*** 请求锁的超时时间(ms)*/private Integer waitMinute = WAIT_MINUTE;private TimeUnit timeUnit = TIME_UNIT;/*** Instantiates a new Redis lock.** @param lockKey the lock key*/public RedisLock(String lockKey) {this.lockKey = lockKey;}/*** Instantiates a new Redis lock.** @param lockKey the lock key* @param expire  the expire*/public RedisLock(String lockKey, Long expire) {this.lockKey = lockKey;this.expire = expire;}/*** Instantiates a new Redis lock.** @param lockKey  the lock key* @param expire   the expire* @param timeUnit the time unit*/public RedisLock(String lockKey, Long expire, TimeUnit timeUnit) {this.lockKey = lockKey;this.expire = expire;this.timeUnit = timeUnit;}/*** Instantiates a new Redis lock.** @param lockKey    the lock key* @param expire     the expire* @param timeUnit   the time unit* @param waitMinute the wait minute*/public RedisLock(String lockKey, Long expire, TimeUnit timeUnit, Integer waitMinute) {this.lockKey = lockKey;this.expire = expire;this.timeUnit = timeUnit;this.waitMinute = waitMinute;}/*** Try lock boolean.** @return the boolean*/public boolean tryLock(){try {if (StringUtils.isBlank(lockKey)) {LOG.debug("tryLock:key is blank");return false;}String value = UUID.fastUUID().toString();StringRedisTemplate redisTemplate = SpringUtils.getBean(StringRedisTemplate.class);locked = redisTemplate.opsForValue().setIfAbsent(lockKey, value, expire, timeUnit);// 取锁成功,直接返回falseif (locked) {LOG.debug("tryLock:取锁成功");return locked;} else {if (waitMinute == null) {LOG.debug("tryLock: 等待加锁时间为null,则不再尝试去加锁,直接返回false");return false;}if (waitMinute < 0) {LOG.debug("tryLock: 等待加锁时间小于0,则不再尝试去加锁,直接返回false");return false;}long loseTime = DateUtil.offsetMinute(new Date(), waitMinute).getTime();// 不断尝试获取锁成功返回while (System.currentTimeMillis() < loseTime) {locked = redisTemplate.opsForValue().setIfAbsent(lockKey, value, expire, timeUnit);// 加锁成功if (locked) {return locked;}try {Thread.sleep(WAITING_SECONT);} catch (InterruptedException e) {LOG.error(e, "tryLock 等待加锁的时候异常");}}return locked;}} catch (Exception e) {LOG.error(e, "tryLock error");return false;}}/*** Is locked boolean.** @return the boolean*/public boolean isLocked(){return locked;}/*** Unlock.*/public void unlock(){StringRedisTemplate redisTemplate = SpringUtils.getBean(StringRedisTemplate.class);redisTemplate.delete(lockKey);}

redis_service_196">redis锁 service接口类

/*** 根据key取锁* @param key 健值* @return RedisLock*/RedisLock getLock(String key);/*** 根据key取锁* @param key 健值* @param expire 过期时间* @return RedisLock*/RedisLock getLock(String key, Long expire);/*** 根据key取锁* @param key 健值* @param expire 过期时间* @param timeUnit 过期时间单位* @return RedisLock*/RedisLock getLock(String key, Long expire, TimeUnit timeUnit);/*** 根据key取锁,可以设置等待时间和过期时间* @param key key* @param waitMinute 等待时间,单位是分钟,在这个时间内会多次尝试获取锁,超过这个时间还没获得锁,就返回false* @param expire 加锁过期时间,为null时候,默认为-1L* @param timeUnit 单位,为null默认为Minutes* @return boolean true 成功,false 失败*/RedisLock getLock(String key, Long expire, TimeUnit timeUnit, Integer waitMinute);/*** 释放锁* @param redisLock 锁对象* @date 2020年9月29日14:55:54*/void unlock(RedisLock redisLock);

redis_service_241">redis锁 service实现类

@DubboService
public class RedisLockServiceImpl implements IRedisLockService {private static final Log LOG = LogFactory.get(RedisLockServiceImpl.class);@Overridepublic RedisLock getLock(String key) {if (StringUtils.isBlank(key)) {LOG.error("getLock: key is null");throw new BusinessException("取RedisLock的key不能为空");}return new RedisLock(key);}@Overridepublic RedisLock getLock(String key, Long expire) {if (expire == null) {LOG.debug("getLock: expire is null");return this.getLock(key);}return new RedisLock(key, expire);}@Overridepublic RedisLock getLock(String key, Long expire, TimeUnit timeUnit) {if (timeUnit == null) {LOG.debug("getLock: timeUnit is null");return this.getLock(key, expire);}return new RedisLock(key, expire, timeUnit);}@Overridepublic RedisLock getLock(String key, Long expire, TimeUnit timeUnit, Integer waitMinute) {if (waitMinute == null) {LOG.debug("getLock: waitMinute is null");return this.getLock(key, expire, timeUnit);}return new RedisLock(key, expire, timeUnit, waitMinute);}@Overridepublic void unlock(RedisLock redisLock) {if (redisLock != null) {redisLock.unlock();}}

简单的运用

    @Override@Transactionalpublic void updateUser(V3User user) {//新增用户后立马更新用户 可能出现并发情况 导致数据重复String lockKey = "employeeResume::" + user.getId();RedisLock lock = redisLockService.getLock(lockKey, 10L, TimeUnit.SECONDS, 1);boolean locked = lock.tryLock();// 加锁失败,说明已经有别的程序在执行下面的保存操作,直接返回成功if (!locked) {return;}try {具体实现内容} finally {if (lock != null && lock.isLocked()) {lock.unlock();}}}

http://www.ppmy.cn/ops/144876.html

相关文章

Android Studio打开一个外部的Android app程序

背景描述&#xff1a; 由于Android Studio环境的差异&#xff0c;从网上或者Git下载的一个Android开源项目&#xff0c;用自己的Android Studio加载打开时经常遇到各种问题。那么&#xff0c;有没有什么方法或者步骤可以快速的将一个已存在的android项目导入到自己的Android S…

云手机方案总结

精准把握账号基础设置 1.环境配置要合规真实&#xff1a;无论是在哪个国家或地区开展 TikTok 营销&#xff0c;都要确保云手机的网络环境、语言、时区、GPS 定位等设置与当地实际相符&#xff0c;选择稳定可靠的海外 IP 服务提供商&#xff0c;配置纯净独立的 IP&#xff0c;避…

【算法】一维二维数组前缀和,以及计算二维矩阵中的子矩阵和

前缀和的概念 通过构建一个前缀和数组&#xff0c;我们可以在常数时间&#xff08;O(1)&#xff09;内使用前缀和数组计算任意子数组或子矩阵的和。 简单来说&#xff0c;就是把前面的项加在一起&#xff0c;使得新构建的前缀和数组中每一项都是原数组对应项之前的总和。 一…

Java文字识别OCR API-手写文字识别-生僻字识别-应用场景

在信息爆炸的今天&#xff0c;数据如同氧气一般渗透到生活的每一个角落。而如何高效地获取、处理和利用这些海量的数据&#xff0c;则成为了推动社会进步的关键因素之一。文字识别&#xff08;OCR, Optical Character Recognition&#xff09;接口技术的出现&#xff0c;就像一…

【HTML】动态闪烁圣诞树+雪花+音效

效果展示 使用方法&#xff1a; 1、桌面新建文本文档.txt 2、下述代码复制至文本文档中 3、修改t后缀txt修改为html 4、双击点开 完整代码自取 <!DOCTYPE html> <html lang"en" ><head><meta charset"UTF-8"><title>M…

无人设备遥控器之定向天线篇

一、定义与功能 定向天线&#xff0c;顾名思义&#xff0c;是通过改变天线的辐射方向&#xff0c;实现信号发射、接收和增强的天线。它可以让信号以更高的功率、更远的距离传输到指定区域&#xff0c;同时也能够降低与周围天线之间的干扰。在无人设备遥控器中&#xff0c;定向天…

Linux Shell 基础教程⑧

Shell 教程 Shell 是一个用 C 语言编写的程序&#xff0c;它是用户使用 Linux 的桥梁。Shell 既是一种命令语言&#xff0c;又是一种程序设计语言。 Shell 是指一种应用程序&#xff0c;这个应用程序提供了一个界面&#xff0c;用户通过这个界面访问操作系统内核的服务。 Ke…

redis库基础知识

redis库 Redis 是一个开源的内存数据库&#xff0c;提供了丰富的方法和命令来操作和管理数据库中的数据。下面是 Redis 库中一些常用的方法的介绍&#xff1a; set(key, value): 设置指定键的值get(key): 获取指定键的值delete(key): 删除指定的键和对应的值exists(key): 判断…