基于 redis 的分布式锁的实现

基于 redis 的分布式锁的实现

一:第一种加锁方式(使用 Redis 的setnx命令实现分布)(7 万并发以下没有什么大的问题)

需要解决的问题

1:代码中出现异常会导致锁一直持有.(释放锁时在 finally{}的代码块中进行,不然中间代码出现异常时会导致锁不会进行释放).

2:在系统宕机或者异常时锁一直持有(设置锁的时间).

3:设置锁的时间问题,如果设置锁的时间比执行锁中间的代码的时间小的话,会导致锁被提前释放()(解决方案使用一个 Timer去一直去检查代码是否执行完,没有就去增加锁的持有时间)

4:redis 要搭建集群环境(可能出现主服务器挂了,从服务器没有把数据同步过去导致脏数据)

 @RequestMapping("deductStock")
    public String deductStock(){
        String redisLock = "sjf1";
        String clientId = UUID.randomUUID().toString();
        try {
          	//获取锁  
            Boolean a = redisTemplate.opsForValue().setIfAbsent(redisLock, clientId,10,TimeUnit.SECONDS);
          	//没有获取到锁直接返回
            if (a == false){
                return "没有抢到锁";
            }
            //获取库存进行判断
            int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));
            if (stock > 0){
                int realStock = stock - 1;
                redisTemplate.opsForValue().set("stock",realStock + "");
                System.out.println("扣除库存成功,剩余库存"+realStock);
                return "扣除库存成功,剩余库存"+realStock + " a= " +  a;
            }else {
                System.out.println("扣减失败,库存不足");
                return "扣减失败,库存不足" + " a= " +  a;
            }
        }finally {
            if (clientId.equals(redisTemplate.opsForValue().get(redisLock))){
                redisTemplate.delete(redisLock);
            }
        }
    }

2:第二种加锁方式(redisson)(近乎完美)

1:秒杀场景下导致 Redis 压力过大(可以将库存进行分段实现分段加锁)

分段加锁可能出现一些问题(每段库存大小,这段库存不够跳到下个加锁代码段)

https://blog.csdn.net/u010391342/article/details/84372342

@RequestMapping("deductRedisStock")
    public String deductRedisStock(){
        String redisLock = "sjf";
      	//获取锁
        RLock lock = redisson.getLock(redisLock);
        try {
          	//加锁
            lock.lock();
            int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));
            if (stock > 0){
                int realStock = stock - 1;
                redisTemplate.opsForValue().set("stock",realStock + "");
                System.out.println("扣除库存成功,剩余库存"+realStock);
                return "扣除库存成功,剩余库存"+realStock;
            }else {
                System.out.println("扣减失败,库存不足");
                return "扣减失败,库存不足";
            }
        }finally {
          	//释放锁
            lock.unlock();
        }
    }
附:配置

aplication.yml 文件配置

server:
  port: 8002
spring:
  redis:
    host: 192.168.2.9
    port: 6379
    password:
    timeout: 1000
    database: 1
    pool:
      max-active: 8 #最大连接数
      max-idle: 8 #最大空闲连接数
      max-wait: -1 #最大等待时间
      min-idle: 0
#下面是 Redis 集群配置
#    sentinel:
#      master: master1
#      nodes: 172.16.33.216:16001,172.16.33.216:16002
  main:
    allow-bean-definition-overriding: true

pow 文件配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<!--<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.0.M4</version>
		<relativePath/> &lt;!&ndash; lookup parent from repository &ndash;&gt;
	</parent>-->
	<groupId>com.lock</groupId>
	<artifactId>redis-lock</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>redis-lock</name>
	<description>Demo project for Spring Boot</description>
	<packaging>war</packaging>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.3.RELEASE</version>
		<relativePath/>
	</parent>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
			<!--<exclusions>
				<exclusion>
					<groupId>io.lettuce</groupId>
					<artifactId>lettuce-core</artifactId>
				</exclusion>
			</exclusions>-->
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.redisson</groupId>
			<artifactId>redisson</artifactId>
			<version>2.2.13</version>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>io.projectreactor</groupId>
			<artifactId>reactor-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.7.3</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.68</version>
		</dependency>
	</dependencies>

	<repositories>
		<repository>
			<id>nexus-aliyun</id>
			<name>Nexus aliyun</name>
			<layout>default</layout>
			<url>http://maven.aliyun.com/nexus/content/groups/public</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
			<releases>
				<enabled>true</enabled>
			</releases>
		</repository>
	</repositories>
	<profiles>
		<!--本地环境-->
		<profile>
			<id>local</id>
			<properties>
				<profileActive>local</profileActive>
			</properties>
			<activation>
				<activeByDefault>true</activeByDefault>
			</activation>
		</profile>
		<!-- 测试环境-->
		<profile>
			<id>dev</id>
			<properties>
				<profileActive>dev</profileActive>
			</properties>
		</profile>
		<!--生产环境-->
		<profile>
			<id>prod</id>
			<properties>
				<profileActive>prod</profileActive>
			</properties>
		</profile>
	</profiles>

	<build>

		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>2.0.6.RELEASE</version>
				<configuration>
					<mainClass>com.lock.redislock.RedisLockApplication</mainClass>
					<layout>ZIP</layout>
				</configuration>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
		<resources>
			<!--<resource>
				<directory>src/main/resources</directory>
				<filtering>true</filtering>
				<excludes>
					<exclude>application-*.yml</exclude>
					<exclude>application.yml</exclude>
				</excludes>
			</resource>-->
			<resource>
				<directory>src/main/resources</directory>
				<filtering>true</filtering>
				<includes>
					<include>application-*.yml</include>
					<include>redisson-*.yml</include>
					<include>application.yml</include>
				</includes>
			</resource>
		</resources>
	</build>
</project>

@Bean
	public Redisson getRedisson(){
		Config config = new Config();
		//单机模式  依次设置redis地址和密码
		config.useSingleServer().
				setAddress("192.168.2.9:6379").setDatabase(1);
		return (Redisson)Redisson.create(config);
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值