代码拉取完成,页面将自动刷新
接口A
对数据非常敏感,要求 100% 不能丢数据,那么他可以使用使用基于MySQL的幂等实现方案接口B
对数据不是很敏感,但对性能要求非常高,非常极端的情况下可以容忍一部分error,那么可以采用基于Redis的幂等实现方案enhance-boot-idempotent
)进行自定义扩展(可基于IdempotentEntity
自由的实现扩展)注解 + spel
】的幂等功能实现,使用者可快速简单的使用注解实现业务幂等IdempotentExceptionEventHandler
)以供使用方对极端情况下存在的幂等异常进行自定义兜底由于项目暂时没有发布到中央maven仓库,所以需要自己mvn install 到自己本地maven仓库
源码地址:https://gitee.com/mr_wenpan/basis-enhance/blob/master/enhance-boot-data-redis/README.md
执行命令:mvn clean install
(需要切换到该项目目录下执行)
enhance-idempotent-adapter-db
或 enhance-idempotent-adapter-redis
即可<dependencies>
<!--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--==================================使用基于MySQL的幂等组件实现时才引入如下依赖==========================-->
<!--基于db实现幂等-->
<dependency>
<groupId>org.basis.enhance</groupId>
<artifactId>enhance-idempotent-adapter-db</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--如果项目里已经有了MySQL和mybatis相关依赖和配置,则可以不引入如下配置-->
<!--mysql相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!--==================================使用基于MySQL的幂等组件实现时才引入如上依赖==========================-->
<!--==================================使用基于redis的幂等组件实现时才引入如下依赖==========================-->
<!--基于redis实现幂等-->
<dependency>
<groupId>org.basis.enhance</groupId>
<artifactId>enhance-idempotent-adapter-redis</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--如果项目里已经有了redis相关依赖和配置,则可以不引入如下配置-->
<!--redis核心依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--Apache的 common-pool2 提供连接池,供redis客户端使用-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--==================================使用基于redis的幂等组件实现时才引入如上依赖==========================-->
</dependencies>
primaryRepository
server:
port: 12345
# 幂等组件核心配置
enhance:
idempotent:
# 开启幂等组件
enable: true
namespace: idempotent-test
# 期望的最大执行时间是1天
maxProcessTime: 1
unit: DAYS
# 开启多个实现时,指定哪个是primary
primaryRepository: redisIdempotentRepository
# 适配器选择(任选一种模式开启即可)
adapter:
redis:
# 开启基于Redis的幂等实现
enable: true
# 幂等记录存放有效时间是120天
expireTime: 120
unit: DAYS
mysql:
# 开启基于MySQL的幂等实现
enable: false
spring:
application:
name: idempotent-demo
# mysql连接配置(基于MySQL实现幂等需要MySQL相关连接配置)
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: ${SPRING_DATASOURCE_URL:jdbc:mysql://ip-host:3306/xxxDB?useUnicode=true&characterEncoding=UTF-8&useSSL=false}
username: ${SPRING_DATASOURCE_USERNAME:xxx}
password: ${SPRING_DATASOURCE_PASSWORD:xxxx}
# redis基础配置(基于Redis实现幂等需要Redis相关连接配置)
redis:
host: ${SPRING_REDIS_HOST:wenpan-host}
port: ${SPRING_REDIS_PORT:6379}
password: ${SPRING_REDIS_PASSWORD:xxxx}
database: ${SPRING_REDIS_DATABASE:2}
# 指定client类型
client-type: lettuce
lettuce:
pool:
# 资源池中最大连接数,默认8,-1表示无限制;可根据服务并发redis情况及服务端的支持上限调整
max-active: ${SPRING_REDIS_POOL_MAX_ACTIVE:16}
# 资源池运行最大空闲的连接数
# 默认8,-1表示无限制;可根据服务并发redis情况及服务端的支持上限调整,一般建议和max-active保持一致,避免资源伸缩带来的开销
max-idle: ${SPRING_REDIS_POOL_MAX_IDLE:16}
# 当资源池连接用尽后,调用者的最大等待时间(单位为毫秒) 默认 -1 表示永不超时,设置5秒
max-wait: ${SPRING_REDIS_POOL_MAX_WAIT:5000}
mybatis:
mapperLocations: classpath*:/mapper/*.xml
configuration:
mapUnderscoreToCamelCase: true
SQL脚本位置:enhance-boot-idempotent/enhance-idempotent-adapter-db/src/main/resources/sql
CREATE TABLE `business_idempotent` (
`idempotent_id` bigint NOT NULL AUTO_INCREMENT COMMENT '幂等主键',
`namespace` varchar(32) DEFAULT NULL COMMENT '命名空间',
`source` varchar(64) DEFAULT NULL COMMENT '来源',
`operation_type` varchar(64) DEFAULT NULL COMMENT '操作类型',
`business_key` varchar(128) NOT NULL COMMENT '业务key',
`unique_key` varchar(255) NOT NULL COMMENT '唯一键(用于幂等控制)',
`idempotent_status` tinyint NOT NULL COMMENT '幂等状态(1为处理中,2为处理成功)',
`object_version_number` bigint NOT NULL COMMENT '版本号',
`response` blob COMMENT '响应数据',
`create_date` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
`last_modified_date` datetime NOT NULL COMMENT '最近修改时间',
PRIMARY KEY (`idempotent_id`),
UNIQUE KEY `udx_unique_key` (`unique_key`) USING BTREE COMMENT '幂等键唯一索引'
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='业务幂等表';
@Slf4j
@RestController("TestRedisIdempotentController.v1")
@RequestMapping("/v1/idempotent")
public class TestIdempotentController {
/**
* 测试idempotentHelper执行有返回值的方法
* url: localhost:12345/v1/idempotent/test-with-result?source=taobao&operationType=publish_product&businessKey=pd_20230105007&name=lisi
*/
@GetMapping("/test-with-result")
public String testWithResult(String source,
String operationType,
String businessKey,
String name) {
// 带返回值的幂等执行
String result = idempotentHelper.invoke(source, operationType, businessKey,
() -> testIdempotentService.testIdempotentHelper(name));
log.info("=============>>>>>>> TestRedisIdempotentController result {}", result);
return result;
}
/**
* 测试idempotentHelper执行没有返回值的方法
* url : localhost:12345/v1/idempotent/test-with-no-result?source=taobao&operationType=publish_product&businessKey=pd_20230105008&name=zhangsan
*/
@GetMapping("/test-with-no-result")
public String testWithNoResult(String source,
String operationType,
String businessKey,
String name) {
// 不带返回值的幂等执行
idempotentHelper.invokeWithNoResult(source, operationType, businessKey,
() -> testIdempotentService.testIdempotentWithNoResult(name));
log.info("=============>>>>>>> TestRedisIdempotentController testWithNoResult.");
return "success";
}
}
@Slf4j
@Service
public class TestIdempotentAnnotationServiceImpl implements TestIdempotentAnnotationService {
/**
* 用orderEntity对象里的orderNumber作为业务幂等键
*/
@Idempotent(operationType = "'addOrder'", source = "#orderEntity.platformCode", businessKey = "#orderEntity.orderNumber")
@Override
public OrderEntity addOrder(OrderEntity orderEntity) {
log.info("TestIdempotentAnnotationServiceImpl#addOrder orderEntity is : {}", JSON.toJSONString(orderEntity));
// 模拟修改了订单一些信息
orderEntity.setCreateDate(LocalDateTime.now());
orderEntity.setLastModifyDate(LocalDateTime.now());
orderEntity.setOrderStatus(orderEntity.getOrderStatus() + 1);
// 新增订单逻辑....
return orderEntity;
}
/**
* 用orderEntity对象里的orderLineEntityList集合里的第一个元素的skuCode作为业务幂等键
*/
@Idempotent(operationType = "'modifyOrder'",
source = "#orderEntity.platformCode",
businessKey = "#orderEntity.orderLineEntityList[0].skuCode")
@Override
public OrderEntity modifyOrder(OrderEntity orderEntity) {
log.info("TestIdempotentAnnotationServiceImpl#modifyOrder orderEntity is : {}", JSON.toJSONString(orderEntity));
// 模拟修改了订单一些信息
orderEntity.setCreateDate(LocalDateTime.now());
orderEntity.setLastModifyDate(LocalDateTime.now());
orderEntity.setOrderStatus(orderEntity.getOrderStatus() + 1);
// 修改订单逻辑....
return orderEntity;
}
}
详细案例参考:org.enhance.idempotent.demo.api.controller.TestIdempotentController
和org.enhance.idempotent.demo.app.service.impl.TestIdempotentAnnotationServiceImpl
IdempotentRepository
接口,实现对应的操作幂等记录的方法,然后注入容器即可!DefaultIdempotentExceptionEventHandler
来处理,处理方式是提交到线程池进行日志输出(也可以自己定制线程池覆盖DefaultIdempotentExceptionEventHandler
所使用的线程池)org.enhance.idempotent.core.handler.IdempotentExceptionEventHandler
接口并注入容器即可。此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。