SpringCloud+Redis分布锁demo

本文档展示了如何利用Redis实现一个分布式锁的Java示例,包括引入Redis依赖、设计分布式锁实体和配置类,以及在业务方法中使用锁进行并发控制。通过setnx命令设置锁并设置超时时间防止死锁,使用UUID作为标识进行解锁判断。
摘要由CSDN通过智能技术生成

分布式(三)——实现分布式锁里说过可以通过redis实现分布式锁。
构建一个redis实现的分布锁demo,直观的了解分布锁。

一、引入依赖

<!--引入redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-redis</artifactId>
    <version>1.3.8.RELEASE</version>
</dependency>

二、思路

  • 获取锁的时候,通过setnx加锁,锁的value值为一个随机生成的UUID,通过此在释放锁的时候进行判断
  • 获取锁的时候,用expire命令为锁添加一个超时时间,超过这个时间则放弃获取锁(防止死锁
  • 释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放

三、编码

3.1 分布锁实体

/**
 * @author jc_hook
 * @ClassName Lock
 * @Description 分布锁实体
 * @date 2022/6/28
 */
@Data
public class DistributedLock {

    private String name;

    private String value;


    public DistributedLock(String name, String value) {
        this.name = name;
        this.value = value;
    }
}

3.2 分布锁配置类

/**
 * @author jc_hook
 * @ClassName DistributedLockConfig
 * @Description 分布式锁配置
 * @date 2022/6/28
 */
@Slf4j
@Component
public class DistributedLockConfig {

    /**
     * 锁的有效时间,防止死锁
     */
    private final static long LOCK_EXPIRE = 30*1000L;

    /**
     * 默认30ms尝试一次
     */
    private final static long LOCK_TRY_INTERVAL = 30L;

    /**
     * 默认尝试20s
     */
    private final static long LOCK_TRY_TIMEOUT = 20 * 1000L;

    private RedisTemplate template;

    public void setRedisTemplate(RedisTemplate redisTemplate) {
        this.template = redisTemplate;
    }

    /**
     * 尝试获取全局锁
     *
     * @param lock 锁的名称
     * @return true 获取成功,false获取失败
     */
    public boolean tryLock(DistributedLock lock) {
        return getLock(lock, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_EXPIRE);
    }

    /**
     * 尝试获取全局锁
     * SETEX:可以设置超时时间
     *
     * @param lock    锁的名称
     * @param timeout 获取超时时间 单位ms
     * @return true 获取成功,false获取失败
     */
    public boolean tryLock(DistributedLock lock, long timeout) {
        return getLock(lock, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE);
    }

    /**
     * 尝试获取全局锁
     *
     * @param lock        锁的名称
     * @param timeout     获取锁的超时时间
     * @param tryInterval 多少毫秒尝试获取一次
     * @return true 获取成功,false获取失败
     */
    public boolean tryLock(DistributedLock 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(DistributedLock 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(DistributedLock 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<String, String> ops = template.opsForValue();
                    ops.set(lock.getName(), lock.getValue(), lockExpireTime, TimeUnit.MILLISECONDS);
                    return true;
                } else {
                    //存在锁
                    log.debug("lock is exist!!!");
                }

                //尝试超过了设定值之后直接跳出循环
                if (System.currentTimeMillis() - startTime > timeout) {
                    return false;
                }

                //每隔多长时间尝试获取
                Thread.sleep(tryInterval);
            }
            while (template.hasKey(lock.getName()));
        } catch (InterruptedException e) {
            log.error(e.getMessage());
            return false;
        }
        return false;
    }

    /**
     * 获取锁
     * SETNX(SET If Not Exists):当且仅当 Key 不存在时,则可以设置,否则不做任何动作。
     */
    public Boolean getLockNoTime(DistributedLock lock) {
        if (!StringUtils.isEmpty(lock.getName())) {
            return false;
        }

        // setIfAbsent 底层封装命令 是 setNX()
        boolean falg = template.opsForValue().setIfAbsent(lock.getName(), lock.getValue());

        return false;
    }

    /**
     * 释放锁
     */
    public void releaseLock(DistributedLock lock) {
        if (!StringUtils.isEmpty(lock.getName())) {
            template.delete(lock.getName());
        }
    }
}

3.3 业务方法使用锁

@Override
@CacheEvict(cacheNames = "goods",key = "'selectList'")
public void shipment(GoodsEntity goodsEntity){
    distributedLockConfig.setRedisTemplate(redisTemplate);
    Long goodsId = goodsEntity.getId();
    //设置分布式锁
    DistributedLock lock = new DistributedLock(goodsId.toString(),goodsId.toString());
    if(distributedLockConfig.tryLock(lock)){
        try {
            Integer buyNum = goodsEntity.getNum();
            goodsEntity = getBaseMapper().selectById(goodsId);
            //只更新数量
            UpdateWrapper<GoodsEntity> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id",goodsId);
            updateWrapper.set("num",goodsEntity.getNum()-buyNum);
            update(updateWrapper);
        }catch (Throwable ex){
            throw  new RuntimeException("购置商品失败!请联系管理员");
        }
        //释放锁
        distributedLockConfig.releaseLock(lock);
    }

}
### 回答1: springcloud是一个开源的微服务框架,它基于Spring Boot,并提供了一整套解决方案,用于构建分布式系统中的各个微服务。通过使用springcloud,我们可以轻松实现服务注册与发现、负载均衡、断路器、配置中心等功能,简化了微服务开发和管理的复杂度。 springboot是一个基于Spring的轻量级开发框架,它通过开箱即用的原则,提供了一种快速构建应用程序的方式。使用springboot,我们可以简化繁琐的配置,只需少量的代码即可实现一个功能完整的应用程序,并且可以方便地和其他Spring生态的框架进行集成。 OAuth2是一种授权协议,用于保护Web应用程序、移动应用程序和API的资源。通过OAuth2协议,用户可以授权第三方应用程序访问他们的资源,而无需提供他们的密码。它提供了一种安全且可扩展的机制来处理用户身份验证和授权,并且被广泛应用于各种应用程序中。 Spring Security是一个Java框架,用于提供身份验证和访问控制的功能。它可以轻松地集成到Spring应用程序中,提供了一套强大的API和安全策略,用于保护应用程序免受各种攻击,包括身份验证和授权、会话管理、密码加密等。 Redis是一种内存数据存储系统,它以键值对的形式存储数据,并支持多种数据结构,如字符串、列表、集合、有序集合等。Redis具有高速、持久化和可扩展性等特点,可用于缓存、消息队列、分布式锁等各种场景。在使用Spring框架开发时,我们可以使用Redis作为缓存层,提高应用程序的性能和响应速度。 综上所述,Spring Cloud提供了构建和管理微服务的解决方案,Spring Boot简化了应用程序的开发,OAuth2和Spring Security提供了安全和授权的功能,而Redis作为内存数据存储系统,为应用程序提供了可扩展的缓存和数据存储能力。这些技术和框架相互协作,可以帮助开发者更快速、更安全地构建分布式系统。 ### 回答2: Spring Cloud是一个用于构建分布式系统的开发工具包,它提供了多个子项目来解决分布式系统的常见问题,例如服务注册与发现、配置管理、断路器、负载均衡等。Spring Boot是用于简化Spring应用程序开发的工具,它提供了一种自动配置的方式来快速搭建和运行Spring应用。OAuth2是一个开放标准,用于授权访问特定资源,它允许用户使用某个网站的授权信息来访问其他网站上的受保护资源。Spring Security是一个全面的身份验证和授权框架,它提供了一套安全服务,用于保护Web应用程序中的资源。Redis是一个高性能的键值存储系统,它常被用作缓存、队列、消息中间件等。 结合以上几个技术,可以构建一个基于Spring Cloud分布式系统,使用Spring Boot快速搭建各个服务,使用Spring Security进行身份验证和授权管理。而OAuth2可以用于保护系统中的资源,通过认证服务器进行用户认证和授权,使得只有授权的用户才能访问相应的资源。Spring Security与OAuth2可以集成使用,通过Spring Security提供的权限管理功能来管理不同角色对资源的访问权限。同时,将Redis作为缓存服务器,可用于提高系统的性能和响应速度。 总之,Spring CloudSpring Boot、OAuth2、Spring Security和Redis等技术可以在构建分布式系统时发挥重要作用,帮助我们快速搭建实现各个功能模块,并提供高性能和安全性。 ### 回答3: Spring Cloud是一套基于Spring Boot的微服务框架,它提供了在分布式系统中构建和管理各种微服务的解决方案。它具有服务注册与发现、负载均衡、熔断、服务网关等功能,可以方便地实现微服务架构。 Spring Boot是一个用于快速开发基于Spring框架的应用程序的工具,它简化了Spring应用程序的配置和部署流程。它提供了自动化配置、内嵌服务器、开箱即用的特性,使得我们只需要关注业务逻辑的开发而不用过多关注框架的配置。 OAuth2是一种开放标准的授权协议,它使得用户可以通过授权的方式将与用户相关的信息共享给第三方应用程序。它使用令牌的方式进行授权,具有安全性高、可扩展性好的优点,常用于实现单点登录和授权管理。 Spring Security是一个用于在Java应用程序中提供身份验证和访问控制的框架。它可以与Spring Boot和Spring Cloud集成,提供了认证、授权、密码加密等功能,帮助我们更好地保护应用程序的安全。 Redis是一种高性能的键值存储系统,它支持多种数据结构,如字符串、列表、哈希表等。它具有高并发读写、持久化、分布式等特点,常用于缓存、消息队列、会话管理等场景。 综上所述,Spring Cloud提供了构建微服务的解决方案,Spring Boot简化了Spring应用程序的开发,OAuth2实现了授权管理,Spring Security提供了身份验证和访问控制,而Redis则可以用于缓存和数据存储。这些技术的结合可以帮助我们构建安全、高效的分布式系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值