Redisson的正确使用以及封装分布式锁
mhr18 2024-11-09 12:23 44 浏览 0 评论
设置过期时间方式
//注入RedissonClient对象
@Resource
private RedissonClient redissonClient;
public void testLock5() {
RLock lock = redissonClient.getLock("redis:qsl:test");
try {
boolean triedLock = lock.tryLock(1, 3, TimeUnit.SECONDS);
if (triedLock) {
System.out.println(String.format("线程 %s 获取到锁, 执行业务中...", Thread.currentThread().getName()));
TimeUnit.SECONDS.sleep(5);
System.out.println(String.format("线程 %s 业务执行完成", Thread.currentThread().getName()));
} else {
System.out.println("thread-id=" + Thread.currentThread().getId() + " 锁获取失败"
);
testLock5();
}
} catch (Exception e) {
e.printStackTrace();
Thread.currentThread().interrupt();
} finally {
//释放锁
if (lock.isHeldByCurrentThread()) {
System.out.println("thread-id=" + Thread.currentThread().getId()
+ "开始释放锁");
lock.unlock();
System.out.println("thread-id=" + Thread.currentThread().getId()
+ "锁释放成功");
}
}
}
public void multiThreadLock5() throws InterruptedException {
for (int i = 0; i < 2; i++) {
new Thread(this::testLock5).start();
}
TimeUnit.SECONDS.sleep(10);
System.out.println("main 退出");
}
执行结果
线程 Thread-3 获取到锁, 执行业务中...
thread-id=51 锁获取失败
thread-id=51 锁获取失败
thread-id=51 锁获取失败
线程 Thread-4 获取到锁, 执行业务中...
线程 Thread-3 业务执行完成
线程 Thread-4 业务执行完成
main 退出
线程Thread-3首先获得了锁,thread-id=51后进来,取不到锁只能重试,因为代码需要执行5秒,所以到第四秒的时候,线程 Thread-3释放了锁,所以线程 Thread-4 获取到锁, 执行自己的业务,
接着5秒过后线程 Thread-3执行完成,但是他的锁已经在第三秒后被释放了,所以不用执行lock.unlock();到第8秒结束后,线程 Thread-4 业务执行完成,同样的它在第6秒结束后被释放了,所以不用执行lock.unlock();
不设置过期时间的方式
public void multiThreadLock6() throws InterruptedException {
for (int i = 0; i < 2; i++) {
new Thread(this::testLock6).start();
}
TimeUnit.SECONDS.sleep(10);
System.out.println("main 退出");
}
public void testLock6() {
RLock lock = redissonClient.getLock("redis:qsl:test");
try {
boolean triedLock = lock.tryLock(1, TimeUnit.SECONDS);
if (triedLock) {
System.out.println(String.format("线程 %s 获取到锁, 执行业务中...", Thread.currentThread().getName()));
try {
System.out.println("业务处理中...");
} catch (Exception e) {
System.out.println("业务处理异常:" + e.getMessage());
} finally {
lock.unlock();
}
} else {
System.out.println("thread-id=" + Thread.currentThread().getId() + " 锁获取失败"
);
}
} catch (Exception e) {
System.out.println("获职锁或释放锁异常:"+e.getMessage());
}
}
执行结果
线程 Thread-3 获取到锁, 执行业务中...
业务处理中...
线程 Thread-4 获取到锁, 执行业务中...
业务处理中...
main 退出
可以发现Thread-3先获得了锁,在业务执行完成后,释放了锁,Thread-4才能获得锁,依次执行代码。
缺陷:这种方式没有设置锁的过期时间,所以在服务器宕机且没有释放锁的的情况下会出现死锁
我个人其实是更加推荐第一种方式,我们尽量把锁的粒度放到最小,这样出现代码执行时间超过锁超时时间的情况会比较少
自定义封装redisson
pom文件
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- <parent>-->
<!-- <groupId>com.cloud.based</groupId>-->
<!-- <artifactId>cloud-based-core</artifactId>-->
<!-- <version>1.0-SNAPSHOT</version>-->
<!-- </parent>-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<artifactId>redis-distributed-lock-core</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.projectlombok</groupId>-->
<!-- <artifactId>lombok</artifactId>-->
<!-- <version>1.16.20</version>-->
<!-- <scope>provided</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
</dependency>
</dependencies>
</project>
定义RedissonProperties
/**
* @Description: 读取redis配置信息,封装到当前实体中
*
* @author xub
* @date 2019/6/19 下午9:35
*/
@PropertySource({"classpath:redisson.properties"})
@ConfigurationProperties(prefix = "redisson.lock.server")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RedissonProperties {
/**
* redis主机地址,ip:port,有多个用半角逗号分隔
*/
private String address;
/**
* 连接类型,支持standalone-单机节点,sentinel-哨兵,cluster-集群,masterslave-主从
*/
private String type;
/**
* redis 连接密码
*/
private String password;
/**
* 选取那个数据库
*/
private int database;
public RedissonProperties setPassword(String password) {
this.password = password;
return this;
}
public RedissonProperties setDatabase(int database) {
this.database = database;
return this;
}
}
定义GlobalConstant全局常量枚举
package com.cloud.based.redisson.constant;
/**
* @author xub
* @Description: 全局常量枚举 用来拼接完整的URL
* @date 2019/6/19 下午9:09
*/
public enum GlobalConstant {
REDIS_CONNECTION_PREFIX("redis://", "Redis地址配置前缀");
private final String constant_value;
private final String constant_desc;
GlobalConstant(String constant_value, String constant_desc) {
this.constant_value = constant_value;
this.constant_desc = constant_desc;
}
public String getConstant_value() {
return constant_value;
}
public String getConstant_desc() {
return constant_desc;
}
}
定义RedisConnectionTypeRedis连接方式
package com.cloud.based.redisson.constant;
/**
* @desc Redis连接方式
* 包含:standalone-单节点部署方式
* sentinel-哨兵部署方式
* cluster-集群方式
* masterslave-主从部署方式
*
* @author xub
* @date 2019/6/20 下午4:21
*/
public enum RedisConnectionType {
STANDALONE("standalone", "单节点部署方式"),
SENTINEL("sentinel", "哨兵部署方式"),
CLUSTER("cluster", "集群方式"),
MASTERSLAVE("masterslave", "主从部署方式");
private final String connection_type;
private final String connection_desc;
private RedisConnectionType(String connection_type, String connection_desc) {
this.connection_type = connection_type;
this.connection_desc = connection_desc;
}
public String getConnection_type() {
return connection_type;
}
public String getConnection_desc() {
return connection_desc;
}
}
定义RedissonManager管理
package com.cloud.based.redisson;
import com.cloud.based.redisson.constant.RedisConnectionType;
import com.cloud.based.redisson.properties.RedissonProperties;
import com.cloud.based.redisson.strategy.RedissonConfigService;
import com.cloud.based.redisson.strategy.impl.ClusterConfigImpl;
import com.cloud.based.redisson.strategy.impl.MasterslaveConfigImpl;
import com.cloud.based.redisson.strategy.impl.SentineConfigImpl;
import com.cloud.based.redisson.strategy.impl.StandaloneConfigImpl;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.config.Config;
/**
* @Description: Redisson核心配置,用于提供初始化的redisson实例
*
* @author xub
* @date 2019/6/19 下午10:16
*/
@Slf4j
public class RedissonManager {
private Config config = new Config();
private Redisson redisson = null;
public RedissonManager() {
}
public RedissonManager(RedissonProperties redissonProperties) {
try {
//通过不同部署方式获得不同cofig实体
config = RedissonConfigFactory.getInstance().createConfig(redissonProperties);
redisson = (Redisson) Redisson.create(config);
} catch (Exception e) {
log.error("Redisson init error", e);
throw new IllegalArgumentException("please input correct configurations," +
"connectionType must in standalone/sentinel/cluster/masterslave");
}
}
public Redisson getRedisson() {
return redisson;
}
/**
* Redisson连接方式配置工厂
* 双重检查锁
*/
static class RedissonConfigFactory {
private RedissonConfigFactory() {
}
private static volatile RedissonConfigFactory factory = null;
public static RedissonConfigFactory getInstance() {
if (factory == null) {
synchronized (Object.class) {
if (factory == null) {
factory = new RedissonConfigFactory();
}
}
}
return factory;
}
/**
* 根据连接类型获取对应连接方式的配置,基于策略模式
*
* @param redissonProperties redis连接信息
* @return Config
*/
Config createConfig(RedissonProperties redissonProperties) {
Preconditions.checkNotNull(redissonProperties);
Preconditions.checkNotNull(redissonProperties.getAddress(), "redisson.lock.server.address cannot be NULL!");
Preconditions.checkNotNull(redissonProperties.getType(), "redisson.lock.server.password cannot be NULL");
Preconditions.checkNotNull(redissonProperties.getDatabase(), "redisson.lock.server.database cannot be NULL");
String connectionType = redissonProperties.getType();
//声明配置上下文
RedissonConfigService redissonConfigService = null;
if (connectionType.equals(RedisConnectionType.STANDALONE.getConnection_type())) {
redissonConfigService = new StandaloneConfigImpl();
} else if (connectionType.equals(RedisConnectionType.SENTINEL.getConnection_type())) {
redissonConfigService = new SentineConfigImpl();
} else if (connectionType.equals(RedisConnectionType.CLUSTER.getConnection_type())) {
redissonConfigService = new ClusterConfigImpl();
} else if (connectionType.equals(RedisConnectionType.MASTERSLAVE.getConnection_type())) {
redissonConfigService = new MasterslaveConfigImpl();
} else {
throw new IllegalArgumentException("创建Redisson连接Config失败!当前连接方式:" + connectionType);
}
return redissonConfigService.createRedissonConfig(redissonProperties);
}
}
}
定义RedissonConfigService Redisson配置构建接口
package com.cloud.based.redisson.strategy;
import com.cloud.based.redisson.properties.RedissonProperties;
import org.redisson.config.Config;
/**
* @Description: Redisson配置构建接口
*
* @author xub
* @date 2019/6/20 下午3:35
*/
public interface RedissonConfigService {
/**
* 根据不同的Redis配置策略创建对应的Config
* @param redissonProperties
* @return Config
*/
Config createRedissonConfig(RedissonProperties redissonProperties);
}
定义ClusterConfigImpl cluster连接方式
package com.cloud.based.redisson.strategy.impl;
import com.cloud.based.redisson.constant.GlobalConstant;
import com.cloud.based.redisson.properties.RedissonProperties;
import com.cloud.based.redisson.strategy.RedissonConfigService;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.config.Config;
/**
* @Description: 集群方式Redisson部署
* 地址格式:
* cluster方式至少6个节点(3主3从,3主做sharding,3从用来保证主宕机后可以高可用)
* 格式为: 127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
*
* @author xub
* @date 2019/6/19 下午4:24
*/
@Slf4j
public class ClusterConfigImpl implements RedissonConfigService {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
String[] addrTokens = address.split(",");
//设置cluster节点的服务IP和端口
for (int i = 0; i < addrTokens.length; i++) {
config.useClusterServers()
.addNodeAddress(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + addrTokens[i]);
if (StringUtil.isNotBlank(password)) {
config.useClusterServers().setPassword(password);
}
}
log.info("初始化[集群部署]方式Config,redisAddress:" + address);
} catch (Exception e) {
log.error("集群部署 Redisson init error", e);
e.printStackTrace();
}
return config;
}
}
定义MasterslaveConfigImpl 主从部署
package com.cloud.based.redisson.strategy.impl;
import com.cloud.based.redisson.constant.GlobalConstant;
import com.cloud.based.redisson.properties.RedissonProperties;
import com.cloud.based.redisson.strategy.RedissonConfigService;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.config.Config;
import java.util.ArrayList;
import java.util.List;
/**
* @Description: 主从部署Redisson配置
* 连接方式: 主节点,子节点,子节点
* 格式为: 127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381
* @author xub
* @date 2019/6/19 下午9:21
*/
@Slf4j
public class MasterslaveConfigImpl implements RedissonConfigService {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
int database = redissonProperties.getDatabase();
String[] addrTokens = address.split(",");
String masterNodeAddr = addrTokens[0];
//设置主节点ip
config.useMasterSlaveServers().setMasterAddress(masterNodeAddr);
if (StringUtil.isNotBlank(password)) {
config.useMasterSlaveServers().setPassword(password);
}
config.useMasterSlaveServers().setDatabase(database);
//设置从节点,移除第一个节点,默认第一个为主节点
List<String> slaveList = new ArrayList<>();
for (String addrToken : addrTokens) {
slaveList.add(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + addrToken);
}
slaveList.remove(0);
config.useMasterSlaveServers().addSlaveAddress((String[]) slaveList.toArray());
log.info("初始化[主从部署]方式Config,redisAddress:" + address);
} catch (Exception e) {
log.error("主从部署 Redisson init error", e);
e.printStackTrace();
}
return config;
}
}
定义SentineConfigImpl 哨兵集群
package com.cloud.based.redisson.strategy.impl;
import com.cloud.based.redisson.constant.GlobalConstant;
import com.cloud.based.redisson.properties.RedissonProperties;
import com.cloud.based.redisson.strategy.RedissonConfigService;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.config.Config;
/**
* @Description: 哨兵集群部署Redis连接配置
*
* @author xub
* @date 2019/6/19 下午9:17
*/
@Slf4j
public class SentineConfigImpl implements RedissonConfigService {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
int database = redissonProperties.getDatabase();
String[] addrTokens = address.split(",");
String sentinelAliasName = addrTokens[0];
//设置redis配置文件sentinel.conf配置的sentinel别名
config.useSentinelServers().setMasterName(sentinelAliasName);
config.useSentinelServers().setDatabase(database);
if (StringUtil.isNotBlank(password)) {
config.useSentinelServers().setPassword(password);
}
//设置sentinel节点的服务IP和端口
for (int i = 1; i < addrTokens.length; i++) {
config.useSentinelServers().addSentinelAddress(GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + addrTokens[i]);
}
log.info("初始化[哨兵部署]方式Config,redisAddress:" + address);
} catch (Exception e) {
log.error("哨兵部署 Redisson init error", e);
}
return config;
}
}
定义StandaloneConfigImpl 单机部署
package com.cloud.based.redisson.strategy.impl;
import com.cloud.based.redisson.constant.GlobalConstant;
import com.cloud.based.redisson.properties.RedissonProperties;
import com.cloud.based.redisson.strategy.RedissonConfigService;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.config.Config;
/**
* @Description: 单机部署Redisson配置
*
* @author xub
* @date 2019/6/19 下午10:04
*/
@Slf4j
public class StandaloneConfigImpl implements RedissonConfigService {
@Override
public Config createRedissonConfig(RedissonProperties redissonProperties) {
Config config = new Config();
try {
String address = redissonProperties.getAddress();
String password = redissonProperties.getPassword();
int database = redissonProperties.getDatabase();
String redisAddr = GlobalConstant.REDIS_CONNECTION_PREFIX.getConstant_value() + address;
config.useSingleServer().setAddress(redisAddr);
config.useSingleServer().setDatabase(database);
//密码可以为空
if (StringUtil.isNotBlank(password)) {
config.useSingleServer().setPassword(password);
}
log.info("初始化[单机部署]方式Config,redisAddress:" + address);
} catch (Exception e) {
log.error("单机部署 Redisson init error", e);
}
return config;
}
}
定义RedissonAutoConfiguration
package com.cloud.based.redisson.config;
import com.cloud.based.redisson.RedissonLock;
import com.cloud.based.redisson.RedissonManager;
import com.cloud.based.redisson.properties.RedissonProperties;
import org.redisson.Redisson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
/**
* @Description: Redisson自动化配置
*
* @author xub
* @date 2019/6/19 下午11:55
*/
@Configuration
@ConditionalOnClass(Redisson.class)
@EnableConfigurationProperties(RedissonProperties.class)
//@ComponentScan("com.jincou.redisson.annotation")
public class RedissonAutoConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(RedissonAutoConfiguration.class);
@Bean
@ConditionalOnMissingBean
@Order(value = 2)
public RedissonLock redissonLock(RedissonManager redissonManager) {
RedissonLock redissonLock = new RedissonLock(redissonManager);
LOGGER.info("[RedissonLock]组装完毕");
return redissonLock;
}
@Bean
@ConditionalOnMissingBean
@Order(value = 1)
public RedissonManager redissonManager(RedissonProperties redissonProperties) {
RedissonManager redissonManager =
new RedissonManager(redissonProperties);
LOGGER.info("[RedissonManager]组装完毕,当前连接方式:" + redissonProperties.getType() +
",连接地址:" + redissonProperties.getAddress());
return redissonManager;
}
}
定义RedissonLock api
package com.cloud.based.redisson;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import java.util.concurrent.TimeUnit;
/**
* @Description: 针对源码Redisson进行一层封装
*
* @author xub
* @date 2019/6/19 下午10:26
*/
@Slf4j
public class RedissonLock {
private RedissonManager redissonManager;
private Redisson redisson;
public RedissonLock(RedissonManager redissonManager) {
this.redissonManager = redissonManager;
this.redisson = redissonManager.getRedisson();
}
public RedissonLock() {}
/**
* 加锁操作 (设置锁的有效时间)
* @param lockName 锁名称
* @param leaseTime 锁有效时间
*/
public void lock(String lockName, long leaseTime) {
RLock rLock = redisson.getLock(lockName);
rLock.lock(leaseTime,TimeUnit.SECONDS);
}
/**
* 加锁操作 (锁有效时间采用默认时间30秒)
* @param lockName 锁名称
*/
public void lock(String lockName) {
RLock rLock = redisson.getLock(lockName);
rLock.lock();
}
/**
* 加锁操作(tryLock锁,没有等待时间)
* @param lockName 锁名称
* @param leaseTime 锁有效时间
*/
public boolean tryLock(String lockName, long leaseTime) {
RLock rLock = redisson.getLock(lockName);
boolean getLock = false;
try {
getLock = rLock.tryLock( leaseTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.error("获取Redisson分布式锁[异常],lockName=" + lockName, e);
e.printStackTrace();
return false;
}
return getLock;
}
/**
* 加锁操作(tryLock锁,有等待时间)
* @param lockName 锁名称
* @param leaseTime 锁有效时间
* @param waitTime 等待时间
*/
public boolean tryLock(String lockName, long leaseTime,long waitTime) {
RLock rLock = redisson.getLock(lockName);
boolean getLock = false;
try {
getLock = rLock.tryLock( waitTime,leaseTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.error("获取Redisson分布式锁[异常],lockName=" + lockName, e);
e.printStackTrace();
return false;
}
return getLock;
}
/**
* 解锁
* @param lockName 锁名称
*/
public void unlock(String lockName) {
redisson.getLock(lockName).unlock();
}
/**
* 判断该锁是否已经被线程持有
* @param lockName 锁名称
*/
public boolean isLock(String lockName) {
RLock rLock = redisson.getLock(lockName);
return rLock.isLocked();
}
/**
* 判断该线程是否持有当前锁
* @param lockName 锁名称
*/
public boolean isHeldByCurrentThread(String lockName) {
RLock rLock = redisson.getLock(lockName);
return rLock.isHeldByCurrentThread();
}
public RedissonManager getRedissonManager() {
return redissonManager;
}
public void setRedissonManager(RedissonManager redissonManager) {
this.redissonManager = redissonManager;
}
}
自定义注解DistributedLock
package com.cloud.based.redisson.annotation;
import java.lang.annotation.*;
/**
* @Description: 基于注解的分布式式锁
*
* @author xub
* @date 2019/6/19 下午9:22
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DistributedLock {
/**
* 锁的名称
*/
String value() default "redisson";
/**
* 锁的有效时间
*/
int leaseTime() default 10;
/**
* 锁的等待时间
* @return
*/
int waitTime() default 0;
}
自定义aop DistributedLockHandler
package com.cloud.based.redisson.annotation;
import com.cloud.based.redisson.RedissonLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @Description: Redisson分布式锁注解解析器
*
* @author xub
* @date 2019/6/20 下午9:34
*/
@Aspect
@Component
@Slf4j
public class DistributedLockHandler {
@Autowired
RedissonLock redissonLock;
@Around("@annotation(distributedLock)")
public void around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
log.info("[开始]执行RedisLock环绕通知,获取Redis分布式锁开始");
//获取锁名称
String lockName = distributedLock.value();
//获取超时时间,默认10秒
int leaseTime = distributedLock.leaseTime();
int waitTime = distributedLock.waitTime();
if(0==waitTime){
//如果没有设置等待时间,则直接加锁
redissonLock.lock(lockName, leaseTime);
}else {
//加锁并设置锁的最大等待时间
redissonLock.tryLock(lockName, leaseTime,waitTime);
}
try {
log.info("获取Redis分布式锁[成功],加锁完成,开始执行业务逻辑...");
joinPoint.proceed();
} catch (Throwable throwable) {
log.error("获取Redis分布式锁[异常],加锁失败", throwable);
throwable.printStackTrace();
} finally {
//如果该线程还持有该锁,那么释放该锁。如果该线程不持有该锁,说明该线程的锁已到过期时间,自动释放锁
if (redissonLock.isHeldByCurrentThread(lockName)) {
redissonLock.unlock(lockName);
}
}
log.info("释放Redis分布式锁[成功],解锁完成,结束业务逻辑...");
}
}
在resources->META-INF新增spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.cloud.based.redisson.config.RedissonAutoConfiguration
在需要的服务yml中新增
redisson:
lock:
server:
address: xxx:xxx
type: standalone
password: xxxxx
database: 1
代码中直接添加注解使用
package com.cloud.based.controller;
import com.cloud.based.redisson.RedissonLock;
import com.cloud.based.redisson.annotation.DistributedLock;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xub
* @Description: 基于注解的方式 加锁
* @date 2019/6/19 下午11:01
*/
@RestController
@Slf4j
@Api(description = "redisson注解管理", tags = "AnnotatinLockController")
@AllArgsConstructor
public class AnnotatinLockController {
private final RedissonLock redissonLock;
/**
* 模拟这个是商品库存
*/
public static volatile Integer TOTAL = 10;
@ApiOperation("注释性锁定减少库存")
@GetMapping("annotatin-lock-decrease-stock")
@DistributedLock(value="goods", leaseTime=5)
public String lockDecreaseStock() throws InterruptedException {
if (TOTAL > 0) {
TOTAL--;
}
log.info("===注解模式=== 减完库存后,当前库存===" + TOTAL);
return "=================================";
}
}
大功告成
参考代码:
https://gitee.com/youzhibing/qsl-project/tree/master/redisson-spring-boot-demo
https://gitee.com/yangxixi_323/spring-boot-distributed-redisson?_from=gitee_search
参考博客:
https://juejin.cn/post/7394094789270372403
https://www.cnblogs.com/qdhxhz/p/11059200.html
相关推荐
- 【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...
- Pure Storage推出统一数据管理云平台及新闪存阵列
-
PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...
- 对Java学习的10条建议(对java课程的建议)
-
不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...
- SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!
-
官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...
- JDK21有没有什么稳定、简单又强势的特性?
-
佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...
- 「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了
-
在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...
- Java面试题及答案最全总结(2025版)
-
大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...
- 数据库日常运维工作内容(数据库日常运维 工作内容)
-
#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...
- 分布式之系统底层原理(上)(底层分布式技术)
-
作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...
- oracle 死锁了怎么办?kill 进程 直接上干货
-
1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...
- SpringBoot 各种分页查询方式详解(全网最全)
-
一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...
- 《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略
-
《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...
- LoadRunner(loadrunner录制不到脚本)
-
一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...
- Redis数据类型介绍(redis 数据类型)
-
介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...
- RMAN备份监控及优化总结(rman备份原理)
-
今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)