基于redisTemplate实现分布式锁
有两种实现方式
1、获取锁,获取失败不做其他处理 (不推荐)
2、获取锁,如果失败在重试时间内,重复获取(在简单项目中可以使用 美云)

pom.xml

<?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.6.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>simpleRedisLock</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>simpleRedisLock</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

RedisLockUtil

package com.example.simpleredislock;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 设置等待时间,在时间内 循环操作
 */
@Component
@Slf4j
public class RedisLockUtilWithWaittime {

    @Autowired
    private RedisTemplate redisTemplate;

    public static final String LOCKED = "TRUE";
    public static final long EXPIRE = 120L;
    public static final long ONE_MILLI_NANOS = 1000000L;
    public static final long DEFAULT_TIME_OUT = 2000L;
    public static final Random RANDOM = new Random();

    public RedisLockUtilWithWaittime() {
    }

	// 等待时间重复获取
    public <T> T executeSynchOperate(MainOperator<T> operator, String lockCacheKey, long milliTimeout) throws Exception {
        try {
            if (operator != null && lockCacheKey != null && milliTimeout >= 0L) {
                boolean locked = false;
                long startNano = System.nanoTime();
                boolean waitFlag = milliTimeout > 0L;
                long nanoTimeOut = (waitFlag ? milliTimeout : 50L) * 1000000L;
                T resultObj = null;

                try {
                    while(System.nanoTime() - startNano < nanoTimeOut) {
                        if (redisTemplate.opsForValue().setIfAbsent(lockCacheKey, LOCKED, 120L, TimeUnit.SECONDS)) {
                            locked = true;
                            break;
                        }

                        if (!waitFlag) {
                            break;
                        }

                        Thread.sleep(30L, RANDOM.nextInt(500));
                    }

                    resultObj = operator.executeInvokeLogic(locked);
                } catch (Exception ex) {
                    log.error("处理逻辑", ex);
                    throw ex;
                } finally {
                    if (locked) {
                        releaseRedisLock(lockCacheKey);
                    }

                }
                return resultObj;
            } else {
                throw new Exception("参数不合法");
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /** @deprecated */ 
    // 不推荐使用
    @Deprecated
    public <T> T executeSynchOperate(MainOperator<T> operator, String lockCacheKey) throws Exception {
        boolean locked = false;
        T resultObj = null;

        try {
            if (redisTemplate.opsForValue().setIfAbsent(lockCacheKey, LOCKED, 120L, TimeUnit.MICROSECONDS)) {
                locked = true;
            }

            resultObj = operator.executeInvokeLogic(locked);
        } catch (Exception ex) {
            throw ex;
        } finally {
            if (locked) {
                releaseRedisLock(lockCacheKey);
            }

        }

        return resultObj;
    }



    /**
     * 释放锁
     * @param cacheKey
     */
    public boolean releaseRedisLock(final String cacheKey){
        Boolean deleteLock = redisTemplate.delete(cacheKey);
        if (Boolean.TRUE.equals(deleteLock)) {
            return true;
        }
        return false;
    }

    // 函数式接口
    public interface MainOperator<T> {
        boolean HOLD_LOCK_TAG = false;
        T executeInvokeLogic(boolean result) throws Exception;
    }
}

使用

package com.example.simpleredislock;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class SimpleRedisLockApplicationTests {
    @Autowired
    private RedisLockUtilWithWaittime redisLockUtilWithWaittime;

    @Test
    void contextLoads() throws Exception {
        testWithWaittime();
    }

    /**
     * 在时间范围内重复执行操作,直到成功
     * @return
     * @throws Exception
     */
    public String testWithWaittime() throws Exception {
    	String localKey = "myTest_1";
        return redisLockUtilWithWaittime.executeSynchOperate(result -> {
            if (!result) {
                throw new Exception("");
            }
            // 数据库逻辑
            return "ww";
        }, localKey , 5000);
    }
}

在项目启动时,应该把redis中的分布式锁删除。
推荐使用redission 实现分布式锁。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐