千家信息网

怎么在springcloud分布式系统中实现分布式锁

发表于:2025-02-23 作者:千家信息网编辑
千家信息网最后更新 2025年02月23日,本篇内容介绍了"怎么在springcloud分布式系统中实现分布式锁"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,
千家信息网最后更新 2025年02月23日怎么在springcloud分布式系统中实现分布式锁

本篇内容介绍了"怎么在springcloud分布式系统中实现分布式锁"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、简介

一般来说,对数据进行加锁时,程序先通过acquire获取锁来对数据进行排他访问,然后对数据进行一些列的操作,最后需要释放锁。Redis 本身用 watch命令进行了加锁,这个锁是乐观锁。使用 watch命令对于频繁访问的键会引起性能的问题。

二、redis命令介绍

SETNX命令(SET if Not eXists)
当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。

SETEX命令
设置超时时间

GET命令
返回 key 所关联的字符串值,如果 key 不存在那么返回特殊值 nil 。

DEL命令
删除给定的一个或多个 key ,不存在的 key 会被忽略。

三、实现思路

由于redis的setnx命令天生就适合用来实现锁的功能,这个命令只有在键不存在的情况下为键设置值。获取锁之后,其他程序再设置值就会失败,即获取不到锁。获取锁失败。只需不断的尝试获取锁,直到成功获取锁,或者到设置的超时时间为止。

另外为了防治死锁,即某个程序获取锁之后,程序出错,没有释放,其他程序无法获取锁,从而导致整个分布式系统无法获取锁而导致一系列问题,甚至导致系统无法正常运行。这时需要给锁设置一个超时时间,即setex命令,锁超时后,从而其它程序就可以获取锁了。

四、编码实现

本文采用springboot结合redis 取实现的,所以你需要装一个redis。

首先引入创建springboot工程,引入redis 。

   org.springframework.boot   spring-boot-starter-test   test         org.springframework.boot   spring-boot-starter-web           org.springframework.boot   spring-boot-starter-data-redis  

2.创建一个锁类

/** * 全局锁,包括锁的名称 * Created by fangzhipeng on 2017/4/1. */public class Lock {    private String name;    private String value;    public Lock(String name, String value) {        this.name = name;        this.value = value;    }    public String getName() {        return name;    }    public String getValue() {        return value;    }}

3.创建分布式锁的具体方法,思路已经说清楚了,代码注释也写好了,就不讲解了。

import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;/** * Created by fangzhipeng on 2017/4/1. */@Componentpublic class DistributedLockHandler {    private static final Logger logger = LoggerFactory.getLogger(DistributedLockHandler.class);    private final static long LOCK_EXPIRE = 30 * 1000L;//单个业务持有锁的时间30s,防止死锁    private final static long LOCK_TRY_INTERVAL = 30L;//默认30ms尝试一次    private final static long LOCK_TRY_TIMEOUT = 20 * 1000L;//默认尝试20s    @Autowired    private StringRedisTemplate template;    /**     * 尝试获取全局锁     *     * @param lock 锁的名称     * @return true 获取成功,false获取失败     */    public boolean tryLock(Lock lock) {        return getLock(lock, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_EXPIRE);    }    /**     * 尝试获取全局锁     *     * @param lock    锁的名称     * @param timeout 获取超时时间 单位ms     * @return true 获取成功,false获取失败     */    public boolean tryLock(Lock lock, long timeout) {        return getLock(lock, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE);    }    /**     * 尝试获取全局锁     *     * @param lock        锁的名称     * @param timeout     获取锁的超时时间     * @param tryInterval 多少毫秒尝试获取一次     * @return true 获取成功,false获取失败     */    public boolean tryLock(Lock lock, long timeout, long tryInterval) {        return getLock(lock, timeout, tryInterval, LOCK_EXPIRE);    }    /**     * 尝试获取全局锁     *     * @param lock           锁的名称     * @param timeout        获取锁的超时时间     * @param tryInterval    多少毫秒尝试获取一次     * @param lockExpireTime 锁的过期     * @return true 获取成功,false获取失败     */    public boolean tryLock(Lock lock, long timeout, long tryInterval, long lockExpireTime) {        return getLock(lock, timeout, tryInterval, lockExpireTime);    }    /**     * 操作redis获取全局锁     *     * @param lock           锁的名称     * @param timeout        获取的超时时间     * @param tryInterval    多少ms尝试一次     * @param lockExpireTime 获取成功后锁的过期时间     * @return true 获取成功,false获取失败     */    public boolean getLock(Lock lock, long timeout, long tryInterval, long lockExpireTime) {        try {            if (StringUtils.isEmpty(lock.getName()) || StringUtils.isEmpty(lock.getValue())) {                return false;            }            long startTime = System.currentTimeMillis();            do{                if (!template.hasKey(lock.getName())) {                    ValueOperations ops = template.opsForValue();                    ops.set(lock.getName(), lock.getValue(), lockExpireTime, TimeUnit.MILLISECONDS);                    return true;                } else {//存在锁                    logger.debug("lock is exist!!!");                }                if (System.currentTimeMillis() - startTime > timeout) {//尝试超过了设定值之后直接跳出循环                    return false;                }                Thread.sleep(tryInterval);            }            while (template.hasKey(lock.getName())) ;        } catch (InterruptedException e) {            logger.error(e.getMessage());            return false;        }        return false;    }    /**     * 释放锁     */    public void releaseLock(Lock lock) {        if (!StringUtils.isEmpty(lock.getName())) {            template.delete(lock.getName());        }    }}

4.用法:

@AutowiredDistributedLockHandler distributedLockHandler;Lock lock=new Lock("lockk","sssssssss);if(distributedLockHandler.tryLock(lock){ doSomething(); distributedLockHandler.releaseLock();}

五、注意点

在使用全局锁时为了防止死锁采用 setex命令,这种命令需要根据具体的业务具体设置锁的超时时间。另外一个就是锁的粒度性。比如在redis实战中有个案列,为了实现买卖市场交易的功能,把整个交易市场都锁住了,导致了性能不足的情况,改进方案只对买卖的商品进行加锁而不是整个市场。

"怎么在springcloud分布式系统中实现分布式锁"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

命令 尝试 时间 成功 全局 分布式 名称 程序 系统 市场 情况 数据 死锁 中实 业务 内容 功能 思路 性能 更多 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 涉及网络安全案例 数字技术经济数据库 中国云服务器租用排名 融岁软件开发 课设网络安全管理软件 富士康软件开发笔试题深圳 万方数据库如何检索本校教师文献 网络安全法中的网络安全是指 应用软件开发表彰 宝山区良好软件开发服务保障 杭州系统软件开发的公司 信息化和网络安全要点 o2o商城软件开发 中科蓝讯软件开发用什么工具 中科院网络安全教学视频全集 网络技术基础模块判断题道客 数据库角色和用户有什么区别 工程仿真软件开发公司 2022成都软件开发公司排名 湛江服务软件开发外包 网络技术开发及推广合同 网络安全感悟主题 基恩士全系列2维3维数据库 互联网5g科技评论员 软件开发科技公司商业计划书 服务器调查研究的目的和意义 丽水协同软件开发 电脑连网显示输入网络安全密钥 数据库中医系统设计主题 有名的棋牌软件开发
0