基于 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 文件配置


<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.0modelVersion>
	
	<groupId>com.lockgroupId>
	<artifactId>redis-lockartifactId>
	<version>0.0.1-SNAPSHOTversion>
	<name>redis-lockname>
	<description>Demo project for Spring Bootdescription>
	<packaging>warpackaging>

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

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

	<dependencies>

		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-data-redisartifactId>
			
		dependency>

		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-webartifactId>
		dependency>
		<dependency>
			<groupId>org.redissongroupId>
			<artifactId>redissonartifactId>
			<version>2.2.13version>
		dependency>

		<dependency>
			<groupId>org.projectlombokgroupId>
			<artifactId>lombokartifactId>
			<optional>trueoptional>
		dependency>
		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-testartifactId>
			<scope>testscope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintagegroupId>
					<artifactId>junit-vintage-engineartifactId>
				exclusion>
			exclusions>
		dependency>
		<dependency>
			<groupId>io.projectreactorgroupId>
			<artifactId>reactor-testartifactId>
			<scope>testscope>
		dependency>
		
		<dependency>
			<groupId>redis.clientsgroupId>
			<artifactId>jedisartifactId>
			<version>2.7.3version>
		dependency>
		
		<dependency>
			<groupId>com.alibabagroupId>
			<artifactId>fastjsonartifactId>
			<version>1.2.68version>
		dependency>
	dependencies>

	<repositories>
		<repository>
			<id>nexus-aliyunid>
			<name>Nexus aliyunname>
			<layout>defaultlayout>
			<url>http://maven.aliyun.com/nexus/content/groups/publicurl>
			<snapshots>
				<enabled>falseenabled>
			snapshots>
			<releases>
				<enabled>trueenabled>
			releases>
		repository>
	repositories>
	<profiles>
		
		<profile>
			<id>localid>
			<properties>
				<profileActive>localprofileActive>
			properties>
			<activation>
				<activeByDefault>trueactiveByDefault>
			activation>
		profile>
		
		<profile>
			<id>devid>
			<properties>
				<profileActive>devprofileActive>
			properties>
		profile>
		
		<profile>
			<id>prodid>
			<properties>
				<profileActive>prodprofileActive>
			properties>
		profile>
	profiles>

	<build>

		<plugins>
			<plugin>
				<groupId>org.springframework.bootgroupId>
				<artifactId>spring-boot-maven-pluginartifactId>
				<version>2.0.6.RELEASEversion>
				<configuration>
					<mainClass>com.lock.redislock.RedisLockApplicationmainClass>
					<layout>ZIPlayout>
				configuration>
				<executions>
					<execution>
						<goals>
							<goal>repackagegoal>
						goals>
					execution>
				executions>
			plugin>
		plugins>
		<resources>
			
			<resource>
				<directory>src/main/resourcesdirectory>
				<filtering>truefiltering>
				<includes>
					<include>application-*.ymlinclude>
					<include>redisson-*.ymlinclude>
					<include>application.ymlinclude>
				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);
	}

你可能感兴趣的:(分布式,redis,java)