mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 15:21:53 +08:00
增加 Redis 分布式锁
This commit is contained in:
parent
94dfe41153
commit
53db9de93d
@ -38,6 +38,8 @@
|
|||||||
1. Redis 监控:监控 Redis 数据库的使用情况,使用的 Redis Key 管理
|
1. Redis 监控:监控 Redis 数据库的使用情况,使用的 Redis Key 管理
|
||||||
1. Java 监控:基于 Spring Boot Admin 实现 Java 应用的监控
|
1. Java 监控:基于 Spring Boot Admin 实现 Java 应用的监控
|
||||||
1. 链路追踪:基于 SkyWalking 实现性能监控,特别是链路的追踪
|
1. 链路追踪:基于 SkyWalking 实现性能监控,特别是链路的追踪
|
||||||
|
1. 分布式锁:基于 Redis 实现分布式锁,满足并发场景
|
||||||
|
1. 幂等组件:基于 Redis 实现幂等组件,解决重复请求问题
|
||||||
|
|
||||||
### 研发工具
|
### 研发工具
|
||||||
|
|
||||||
@ -45,7 +47,6 @@
|
|||||||
1. 代码生成:前后端代码的生成(Java、Vue、SQL),支持 CRUD 下载
|
1. 代码生成:前后端代码的生成(Java、Vue、SQL),支持 CRUD 下载
|
||||||
1. 系统接口:基于 Swagger 自动生成相关的 RESTful API 接口文档
|
1. 系统接口:基于 Swagger 自动生成相关的 RESTful API 接口文档
|
||||||
1. 数据库文档:基于 Screw 自动生成数据库文档
|
1. 数据库文档:基于 Screw 自动生成数据库文档
|
||||||
1. 幂等组件:基于 Redis 实现幂等组件,解决重复请求问题
|
|
||||||
|
|
||||||
## 在线体验
|
## 在线体验
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"local": {
|
"local": {
|
||||||
"baseUrl": "http://127.0.0.1:8080/api",
|
"baseUrl": "http://127.0.0.1:48080/api",
|
||||||
"token": "test1"
|
"token": "test1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
pom.xml
15
pom.xml
@ -30,6 +30,10 @@
|
|||||||
<druid.version>1.2.4</druid.version>
|
<druid.version>1.2.4</druid.version>
|
||||||
<mybatis-plus.version>3.4.1</mybatis-plus.version>
|
<mybatis-plus.version>3.4.1</mybatis-plus.version>
|
||||||
<redisson.version>3.14.1</redisson.version>
|
<redisson.version>3.14.1</redisson.version>
|
||||||
|
<!-- Config 配置中心相关 -->
|
||||||
|
<apollo.version>1.7.0</apollo.version>
|
||||||
|
<!-- 服务保障相关 -->
|
||||||
|
<lock4j.version>2.2.0</lock4j.version>
|
||||||
<!-- 监控相关 -->
|
<!-- 监控相关 -->
|
||||||
<skywalking.version>8.3.0</skywalking.version>
|
<skywalking.version>8.3.0</skywalking.version>
|
||||||
<spring-boot-admin.version>2.3.1</spring-boot-admin.version>
|
<spring-boot-admin.version>2.3.1</spring-boot-admin.version>
|
||||||
@ -125,7 +129,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ctrip.framework.apollo</groupId>
|
<groupId>com.ctrip.framework.apollo</groupId>
|
||||||
<artifactId>apollo-client</artifactId> <!-- 引入 Apollo Client 库,实现内嵌的配置中心 -->
|
<artifactId>apollo-client</artifactId> <!-- 引入 Apollo Client 库,实现内嵌的配置中心 -->
|
||||||
<version>1.7.0</version>
|
<version>${apollo.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Job 定时任务相关 -->
|
<!-- Job 定时任务相关 -->
|
||||||
@ -134,6 +138,13 @@
|
|||||||
<artifactId>spring-boot-starter-quartz</artifactId>
|
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 服务保障相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
|
||||||
|
<version>${lock4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 监控相关 -->
|
<!-- 监控相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.skywalking</groupId>
|
<groupId>org.apache.skywalking</groupId>
|
||||||
@ -217,7 +228,7 @@
|
|||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.smallbun.screw</groupId>
|
<groupId>cn.smallbun.screw</groupId>
|
||||||
<artifactId>screw-core</artifactId>
|
<artifactId>screw-core</artifactId> <!-- 实现数据库文档 -->
|
||||||
<version>${screw.version}</version>
|
<version>${screw.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
@ -29,7 +29,8 @@ public interface GlobalErrorCodeConstants {
|
|||||||
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
|
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
|
||||||
|
|
||||||
// ========== 自定义错误段 ==========
|
// ========== 自定义错误段 ==========
|
||||||
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求");
|
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
|
||||||
|
ErrorCode CONCURRENCY_REQUESTS = new ErrorCode(901, "请求失败,请稍后重试"); // 并发请求,不允许
|
||||||
|
|
||||||
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
|
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
|
||||||
|
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package cn.iocoder.dashboard.framework.lock4j.config;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ClassUtil;
|
||||||
|
import cn.iocoder.dashboard.framework.lock4j.core.DefaultLockFailureStrategy;
|
||||||
|
import cn.iocoder.dashboard.framework.lock4j.core.Lock4jRedisKeyConstants;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class Lock4jConfiguration {
|
||||||
|
|
||||||
|
static {
|
||||||
|
// 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到
|
||||||
|
// 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举
|
||||||
|
ClassUtil.loadClass(Lock4jRedisKeyConstants.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DefaultLockFailureStrategy lockFailureStrategy() {
|
||||||
|
return new DefaultLockFailureStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package cn.iocoder.dashboard.framework.lock4j.core;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.common.exception.ServiceException;
|
||||||
|
import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
|
import com.baomidou.lock.LockFailureStrategy;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义获取锁失败策略,抛出 {@link cn.iocoder.dashboard.common.exception.ServiceException} 异常
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class DefaultLockFailureStrategy implements LockFailureStrategy {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLockFailure(String key, long acquireTimeout, int acquireCount) {
|
||||||
|
log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取超时时长:{} ms]", Thread.currentThread().getName(), key, acquireTimeout);
|
||||||
|
throw new ServiceException(GlobalErrorCodeConstants.CONCURRENCY_REQUESTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package cn.iocoder.dashboard.framework.lock4j.core;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
|
||||||
|
import static cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine.KeyTypeEnum.HASH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock4j Redis Key 枚举类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface Lock4jRedisKeyConstants {
|
||||||
|
|
||||||
|
RedisKeyDefine LOCK4J = new RedisKeyDefine("分布式锁",
|
||||||
|
"lock4j:%s", // 参数来自 DefaultLockKeyBuilder 类
|
||||||
|
HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* 分布式锁组件,使用 https://gitee.com/baomidou/lock4j 开源项目
|
||||||
|
*/
|
||||||
|
package cn.iocoder.dashboard.framework.lock4j;
|
@ -8,7 +8,7 @@ import java.time.Duration;
|
|||||||
import static cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
|
import static cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redis Key 枚举类
|
* System Redis Key 枚举类
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
### 请求 /get-permission-info 接口 => 成功
|
||||||
|
GET {{baseUrl}}/tool/test-demo/get?id=1
|
||||||
|
Authorization: Bearer {{token}}
|
@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.dashboard.modules.tool.controller.test;
|
package cn.iocoder.dashboard.modules.tool.controller.test;
|
||||||
|
|
||||||
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
import cn.iocoder.dashboard.common.pojo.CommonResult;
|
import cn.iocoder.dashboard.common.pojo.CommonResult;
|
||||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
|
import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
|
||||||
@ -8,6 +9,7 @@ import cn.iocoder.dashboard.modules.tool.controller.test.vo.*;
|
|||||||
import cn.iocoder.dashboard.modules.tool.convert.test.ToolTestDemoConvert;
|
import cn.iocoder.dashboard.modules.tool.convert.test.ToolTestDemoConvert;
|
||||||
import cn.iocoder.dashboard.modules.tool.dal.dataobject.test.ToolTestDemoDO;
|
import cn.iocoder.dashboard.modules.tool.dal.dataobject.test.ToolTestDemoDO;
|
||||||
import cn.iocoder.dashboard.modules.tool.service.test.ToolTestDemoService;
|
import cn.iocoder.dashboard.modules.tool.service.test.ToolTestDemoService;
|
||||||
|
import com.baomidou.lock.annotation.Lock4j;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
@ -21,6 +23,7 @@ import javax.validation.Valid;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
|
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
|
||||||
import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||||
@ -62,7 +65,11 @@ public class ToolTestDemoController {
|
|||||||
@ApiOperation("获得测试示例")
|
@ApiOperation("获得测试示例")
|
||||||
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
|
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
|
||||||
@PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
|
@PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
|
||||||
|
@Lock4j // 分布式锁
|
||||||
public CommonResult<ToolTestDemoRespVO> getTestDemo(@RequestParam("id") Long id) {
|
public CommonResult<ToolTestDemoRespVO> getTestDemo(@RequestParam("id") Long id) {
|
||||||
|
if (true) { // 测试分布式锁
|
||||||
|
ThreadUtil.sleep(5, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
ToolTestDemoDO testDemo = testDemoService.getTestDemo(id);
|
ToolTestDemoDO testDemo = testDemoService.getTestDemo(id);
|
||||||
return success(ToolTestDemoConvert.INSTANCE.convert(testDemo));
|
return success(ToolTestDemoConvert.INSTANCE.convert(testDemo));
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,13 @@ apollo:
|
|||||||
username: ${spring.datasource.username}
|
username: ${spring.datasource.username}
|
||||||
password: ${spring.datasource.password}
|
password: ${spring.datasource.password}
|
||||||
|
|
||||||
|
--- #################### 服务保障相关配置 ####################
|
||||||
|
|
||||||
|
# Lock4j 配置项
|
||||||
|
lock4j:
|
||||||
|
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
|
||||||
|
expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒
|
||||||
|
|
||||||
--- #################### 监控相关配置 ####################
|
--- #################### 监控相关配置 ####################
|
||||||
|
|
||||||
# Actuator 监控端点的配置项
|
# Actuator 监控端点的配置项
|
||||||
|
@ -81,6 +81,13 @@ apollo:
|
|||||||
username: ${spring.datasource.username}
|
username: ${spring.datasource.username}
|
||||||
password: ${spring.datasource.password}
|
password: ${spring.datasource.password}
|
||||||
|
|
||||||
|
--- #################### 服务保障相关配置 ####################
|
||||||
|
|
||||||
|
# Lock4j 配置项
|
||||||
|
lock4j:
|
||||||
|
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
|
||||||
|
expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒
|
||||||
|
|
||||||
--- #################### 监控相关配置 ####################
|
--- #################### 监控相关配置 ####################
|
||||||
|
|
||||||
# Actuator 监控端点的配置项
|
# Actuator 监控端点的配置项
|
||||||
|
Loading…
Reference in New Issue
Block a user