第二十六章 短链服务-冗余双写架构删除和更新消费者开发实战
第1集 冗余双写架构-更新短链消费者开发实战
简介: 短链服务-更新短链-消费者开发实战
具体步骤见代码
第2集 冗余双写架构-更新短链消费者链路测试
简介: 冗余双写架构-更新短链消费者链路测试
具体步骤见代码
第3集 冗余双写架构-删除短链消费者开发实战
简介: 短链服务-删除短链-消费者开发实战
具体步骤见代码
第4集 冗余双写架构-删除短链消费者链路测试和越权修复
简介: 冗余双写架构-删除短链消费者链路测试
-
对数据库操作的时候,一定要防止越权
- 一个是直接RPC调用
- 一个是通过MQ调用
具体步骤见代码
第5集 冗余双写架构-短链服务开发总结
简介: 冗余双写架构-短链服务开发总结
- 短链服务器CRUD
- 冗余双写架构
- 异常队列
- 最终一致性
第二十七章 流量包商品服务需求和库表讲解
第1集 流量包商品服务-业务需求讲解
简介: 流量包商品服务需求讲解
-
流量包需求讲解
- 百度短链案例 https://dwz.cn/console/price
-
流量包商品模型
- 每个套餐都是一个虚拟商品,没库存限制
- 免费版是新用户注册即可获得
- 不同的商品每天限制的创建的条数不一样
- 用户可以叠加使用多个流量包
-
业务难点
- 流量包购买支付(P2)
- 流量包管理
- 免费流量包管理(P1)
- 付费流量包管理(P1)
- 短链业务-流量包业务联动(P1)
第2集 流量包商品服务-数据库表介绍和实体类生成
简介: 流量包商品服务-数据库表介绍
- 数据库表介绍
CREATE TABLE `product` (
`id` bigint NOT NULL,
`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '商品标题',
`detail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '详情',
`img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '图片',
`level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '产品层级:FIRST青铜、SECOND黄金、THIRD钻石',
`old_amount` decimal(16,0) DEFAULT NULL COMMENT '原价',
`amount` decimal(16,0) DEFAULT NULL COMMENT '现价',
`plugin_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '工具类型 short_link、qrcode',
`day_times` int DEFAULT NULL COMMENT '日次数:短链类型',
`total_times` int DEFAULT NULL COMMENT '总次数:活码才有',
`valid_day` int DEFAULT NULL COMMENT '有效天数',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
- 数据库创建
- 插入初始化数据
INSERT INTO `dcloud_shop`.`product` (`id`, `title`, `detail`, `img`, `level`, `old_amount`, `amount`, `plugin_type`, `day_times`, `total_times`, `valid_day`, `gmt_modified`, `gmt_create`) VALUES (1, '青铜会员-默认', '数据查看支持||日生成短链{{dayTimes}}次||限制跳转50次||默认域名', NULL, 'FIRST', 19, 0, 'SHORT_LINK', 2, NULL, 1, '2021-10-14 17:33:44', '2021-10-11 10:49:35');
INSERT INTO `dcloud_shop`.`product` (`id`, `title`, `detail`, `img`, `level`, `old_amount`, `amount`, `plugin_type`, `day_times`, `total_times`, `valid_day`, `gmt_modified`, `gmt_create`) VALUES (2, '黄金会员-月度', '数据查看支持||日生成短链{{dayTimes}}次||限制不限制||默认域名', NULL, 'SECOND', 99, 1, 'SHORT_LINK', 5, NULL, 30, '2021-10-19 14:36:28', '2021-10-11 10:57:47');
INSERT INTO `dcloud_shop`.`product` (`id`, `title`, `detail`, `img`, `level`, `old_amount`, `amount`, `plugin_type`, `day_times`, `total_times`, `valid_day`, `gmt_modified`, `gmt_create`) VALUES (3, '黑金会员-月度', '数据查看支持||日生成短链{{dayTimes}}次||限制不限制||自定义域名', NULL, 'THIRD', 199, 2, 'SHORT_LINK', 8, NULL, 30, '2021-10-19 14:36:30', '2021-10-11 11:01:13');
- MybatisPlus实体类生成
第3集 流量包商品服务-项目基本骨架创建
简介: 流量包商品服务-项目基本骨架创建
- 配置文件增加和默认库表配置
server.port=8005
spring.application.name=dcloud-shop
#服务注册发现
spring.cloud.nacos.discovery.server-addr=120.79.150.146:8848
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
spring.shardingsphere.datasource.names=ds1
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://120.79.150.146:3306/dcloud_shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=class.net168
spring.shardingsphere.datasource.ds0.connectionTimeoutMilliseconds=30000
spring.shardingsphere.datasource.ds0.idleTimeoutMilliseconds=60000
spring.shardingsphere.datasource.ds0.maintenanceIntervalMilliseconds=30000
spring.shardingsphere.datasource.ds0.maxLifetimeMilliseconds=1800000
spring.shardingsphere.datasource.ds0.maxPoolSize=50
spring.shardingsphere.datasource.ds0.minPoolSize=50
spring.shardingsphere.props.sql.show=true
logging.level.root=INFO
- 启动类配置
- controller-service-manager层建立
第4集 流量包商品服务-商品列表和详情接口链路开发
简介: 流量包商品服务-商品列表和详情接口链路开发
- 商品列表接口开发
- 商品详情接口开发
第二十八章 流量包订单模块需求讲解和库表介绍
第1集 流量包订单模块-业务需求讲解
简介: 流量包订单模块-业务需求讲解
- 流量包订单需求讲解
- 需求
- 支持叠加购买
- 效果:1个流量包支持1天创建50条,如果买了两个则支持1天创建100条
- 支持多渠道支付
- 支付宝、微信等
- 开发对接微信V3最新版支付,支付宝支付的参考第一个高并发项目大课
- V2版微信支付对接可以看
- https://detail.tmall.com/item.htm?id=649570556856
- PC端支付宝支付可以看
- https://detail.tmall.com/item.htm?id=646525336722
- 支持叠加购买
第2集 流量包订单-数据库表介绍和实体类生成
简介: 流量包订单-数据库表介绍和实体类生成
- 数据库表
CREATE TABLE `product_order` (
`id` bigint NOT NULL,
`product_id` bigint DEFAULT NULL COMMENT '订单类型',
`product_title` varchar(64) DEFAULT NULL COMMENT '商品标题',
`product_amount` decimal(16,2) DEFAULT NULL COMMENT '商品单价',
`product_snapshot` varchar(2048) DEFAULT NULL COMMENT '商品快照',
`buy_num` int DEFAULT NULL COMMENT '购买数量',
`out_trade_no` varchar(64) DEFAULT NULL COMMENT '订单唯一标识',
`state` varchar(11) DEFAULT NULL COMMENT 'NEW 未支付订单,PAY已经支付订单,CANCEL超时取消订单',
`create_time` datetime DEFAULT NULL COMMENT '订单生成时间',
`total_amount` decimal(16,2) DEFAULT NULL COMMENT '订单总金额',
`pay_amount` decimal(16,2) DEFAULT NULL COMMENT '订单实际支付价格',
`pay_type` varchar(64) DEFAULT NULL COMMENT '支付类型,微信-银行-支付宝',
`nickname` varchar(64) DEFAULT NULL COMMENT '账号昵称',
`account_no` bigint DEFAULT NULL COMMENT '用户id',
`del` int DEFAULT '0' COMMENT '0表示未删除,1表示已经删除',
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`bill_type` varchar(32) DEFAULT NULL COMMENT '发票类型:0->不开发票;1->电子发票;2->纸质发票',
`bill_header` varchar(200) DEFAULT NULL COMMENT '发票抬头',
`bill_content` varchar(200) DEFAULT NULL COMMENT '发票内容',
`bill_receiver_phone` varchar(32) DEFAULT NULL COMMENT '发票收票人电话',
`bill_receiver_email` varchar(200) DEFAULT NULL COMMENT '发票收票人邮箱',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_query` (`out_trade_no`,`account_no`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
- 数据库实体类生成
第3集 流量包订单-数据库表分库分表讲解和配置
简介: 流量包订单-数据库表分库分表讲解和配置
- 业务需求
- 用户查看自己的订单列表
- 数据存储需求(都是前期规划,上线前可以调整分库分表策略和数量)
- 未来2年,短链平台累计5百万用户
- 付费流包记录:
- 一个用户10条/年,总就是5千万条/年,两年是1亿
- 单表不超过1千万数据,需要分10张表
- 进一步延伸,进行水平分表,比如 2张表、4张表、8张 表、16张表
- 分表数:线上分16张表,本地分2张表即可
- 分片key
- account_no作为partitionKey
#----------配置默认数据库,比如短链域名,不分库分表--------------
spring.shardingsphere.sharding.default-data-source-name=ds0
#默认id生成策略
spring.shardingsphere.sharding.default-key-generator.column=id
spring.shardingsphere.sharding.default-key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.default-key-generator.props.worker.id=${workerId}
# 指定product_order表的数据分布情况,配置数据节点,行表达式标识符使用 ${...} 或 $->{...},但前者与 Spring 本身的文件占位符冲突,所以在 Spring 环境中建议使用 $->{...}
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds0.product_order_$->{0..1}
#水平分表策略+行表达式分片
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{ account_no % 2 }
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.sharding-column=account_no
第4集 流量包订单-Manager层CRUD接口开发
简介: 流量包订单-Manager层CRUD接口开发
- 开发Manager层CRUD接口
第5集 流量包订单-基础分表Manager层单元测试
简介: 流量包订单-基础分表Manager层单元测试
- 单元测试
第二十九章 流量包商品服务-下单模块开发和订单防重提交
第1集 流量包商品服务-订单controller相关接口开发
简介: 商品服务-订单controller相关接口开发
- 分页接口开发
- 订单状态查询接口(扫码支付-订单状态检查)
- 下单接口(controller骨架)
- 支付宝支付返回HTML
- 微信支付返回JSON
第2集 流量包商品服务-流量包下单模块链路流程分析讲解
简介: 商品服务-订单下单模块链路流程分析讲解
- 不涉及到商品库存管理
- 防重提交(重点)
- 获取最新的流量包价格
- 订单验价
- 如果有优惠券或者其他抵扣
- 验证前端显示和后台计算价格
- 创建订单对象保存数据库
- 发送延迟消息-用于自动关单(重点)
- 创建支付信息-对接三方支付(重点)
- 回调更新订单状态(重点)
- 支付成功创建流量包(重点)
第3集 流量包商品服务-下单接口链路骨架开发
简介: 商品服务-流量包下单接口链路骨架开发
- 业务流程
- 重防提交(TODO)
- 获取最新的流量包价格
- 订单验价
- 如果有优惠券或者其他抵扣
- 验证前端显示和后台计算价格
- 创建订单对象保存数据库
- 发送延迟消息-用于自动关单(TODO)
- 创建支付信息-对接三方支付(TODO)
- 回调更新订单状态(TODO)
- 支付成功创建流量包(TODO)
- 代码开发
第4集 流量包商品服务-避免重复下单你能想到几种方式
简介:避免复下单常见解决方案
-
开发的项目中可能会出现下面这些情况:
- 前端下单按钮复点击导致订单创建多次
- 网速等原因造成页面卡顿,用户重复刷新提交请求
- 黑客或恶意用户使用postman等http工具重复恶意提交表单
-
问题
- 会导致表单重复提交,造成数据重复或者错乱
- 核心接口的请求增加,消耗服务器负载,严重甚至会造成服务器宕机
-
因此核心接口需要做防重提交,你能想到几种方式
-
方式一:前端JS控制点击次数,屏蔽点击按钮无法点击
- 前端可以被绕过,前端有限制,后端也需要有限制
-
方式二:数据库或者其他存储增加唯一索引约束
- 需要想出满足业务需求的唯一索引约束,比如注册的手机号唯一
-
方式三:服务端token令牌方式
- 下单前先获取令牌-存储redis 下单时一并把token提交并检验和删除-lua脚本
- 分布式情况下,采用Lua脚本进行操作
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
-
- 方式三 是大家采用的最多的,那有没更加优雅的方式呢?
- 采用自定义注解,也有多种方式
第三十章 流量包商品服务-多场景自定义注解防重提交实战
第1集 java核心知识-教你掌握自定义注解
简介:java核心知识-自定义注解
- Annotation(注解)
- 从JDK 1.5开始, Java增加了对元数据(MetaData)的支持,也就是 Annotation(注解)。
- 注解其实就是代码里的特殊标记,它用于替代配置文件
- 常见的很多 @Override、@Deprecated等
- 什么是元注解
- 注解的注解,比如当我们需要自定义注解时
- 会需要一些元注解(meta-annotation),如**@Target和@Retention**
- java内置4种元注解
- @Target 表示该注解用于什么地方
- ElementType.CONSTRUCTOR 用在构造器
- ElementType.FIELD 用于描述域-属性上
- ElementType.METHOD 用在方法上
- ElementType.TYPE 用在类或接口上
- ElementType.PACKAGE 用于描述包
- @Retention 表示在什么级别保存该注解信息
- RetentionPolicy.SOURCE 保留到源码上
- RetentionPolicy.CLASS 保留到字节码上
- RetentionPolicy.RUNTIME 保留到虚拟机运行时(最多,可通过反射获取)
- @Documented 将此注解包含在 javadoc 中
- @Inherited 是否允许子类继承父类中的注解
- @Target 表示该注解用于什么地方
- @interface
- 用来声明一个注解,可以通过default来声明参数的默认值
- 自定义注解时,自动继承了java.lang.annotation.Annotation接口
- 通过反射可以获取自定义注解
第2集 AOP+自定义注解-接口防重提交多场景设计
简介: AOP+自定义注解接口防重提交多场景设计
- 防重提交方式
- token令牌方式
- ip+类+方法方式
- 利用AOP
- Aspect Oriented Program 面向切面编程, 在不改变原有逻辑上增加额外的功能
- AOP思想把功能分两个部分,分离系统中的各种关注点
- 好处
- 减少代码侵入,解耦
- 可以统一处理横切逻辑
- 方便添加和删除横切逻辑
- 业务流程
- 自定义注解
import java.lang.annotation.*;
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatSubmit {
/**
* 加锁过期时间,默认是5秒
* @return
*/
long lockTime() default 5;
/**
* 默认限制类型,是方法参数
* @return
*/
Type limitType() default Type.PARAM;
/**
* 两种类型,token 或者 param
*/
enum Type{ PARAM , TOKEN};
}
第3集 订单防重提交-自定义注解开发实战-Token令牌方式
简介:订单防重提交-自定义注解开发实战-Token令牌方式
- 新增redis配置
#-------redis连接配置-------
spring.redis.client-type=jedis
spring.redis.host=120.79.150.146
spring.redis.password=class.net
spring.redis.port=6379
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-idle=100
spring.redis.jedis.pool.min-idle=100
spring.redis.jedis.pool.max-wait=60000
- 编写接口获取令牌
@Autowired
private StringRedisTemplate redisTemplate;
@GetMapping("token")
public JsonData getToken(){
LoginUser loginUser = LoginInterceptor.threadLocal.get();
String token = CommonUtil.getStringNumRandom(32);
//"order:submit:%s:%s"
String key = String.format(RedisKey.SUBMIT_ORDER_TOKEN_KEY, loginUser.getAccountNo(),requestToken);
redisTemplate.opsForValue().set(key, "1", 30, TimeUnit.MINUTES);
return JsonData.buildSuccess(token);
}
- 定义切面类-开发解析器
/**
* 定义 @Pointcut注解表达式,
* 方式一:@annotation:当执行的方法上拥有指定的注解时生效(我们采用这)
* 方式二:execution:一般用于指定方法的执行
*
* @param repeatSubmit
*/
@Pointcut("@annotation(repeatSubmit)")
public void pointcutNoRepeatSubmit(RepeatSubmit repeatSubmit) {
}
/**
* 环绕通知, 围绕着方法执行
* @Around 可以用来在调用一个具体方法前和调用后来完成一些具体的任务。
*
* 方式一:单用 @Around("execution(* net.class.controller.*.*(..))")可以
* 方式二:用@Pointcut和@Around联合注解也可以(我们采用这个)
*
*
* 两种方式
* 方式一:加锁 固定时间内不能重复提交
* <p>
* 方式二:先请求获取token,这边再删除token,删除成功则是第一次提交
*
* @param joinPoint
* @param noRepeatSubmit
* @return
* @throws Throwable
*/
@Around("pointcutNoRepeatSubmit(noRepeatSubmit)")
public Object around(ProceedingJoinPoint joinPoint, RepeatSubmit noRepeatSubmit) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
boolean res;
String type = noRepeatSubmit.limitType().name();
if (type.equals(RepeatSubmit.Type.PARAM.name())) {
//方式一方法参数 TODO
} else {
//方式二,令牌形式
String requestToken = request.getHeader("request-token");
if (StringUtils.isBlank(requestToken)) {
throw new BizException(BizCodeEnum.ORDER_CONFIRM_TOKEN_EQUAL_FAIL);
}
LoginUser loginUser = LoginInterceptor.threadLocal.get();
//"order:submit:%s:%s"
String key = String.format(RedisKey.SUBMIT_ORDER_TOKEN_KEY, loginUser.getAccountNo(),requestToken);
/**
* 提交表单的token key
* 方式一:不用lua脚本获取再判断,之前是因为 key组成是 order:submit:accountNo, value是对应的token,所以需要先获取值,再判断
* 方式二:可以直接key是 order:submit:accountNo:token,然后直接删除成功则完成
*/
res = stringRedisTemplate.delete(key);
}
if (!res) {
throw new BizException(BizCodeEnum.ORDER_CONFIRM_REPEAT);
}
System.out.println("目标方法执行前");
Object object = joinPoint.proceed();
System.out.println("目标方法执行后");
return object;
}
第4集 Spring里面的AOP常见概念复习巩固
简介:Spring里面的AOP常见概念复习巩固
-
能否解释下AOP里面常见的概念,比如 横切、通知、连接点、切入点、切面 ?
-
横切关注点
- 对哪些方法进行拦截,拦截后怎么处理,这些就叫横切关注点
- 比如 权限认证、日志、事物
-
通知 Advice
- 在特定的切入点上执行的增强处理
- 做啥? 比如你需要记录日志,控制事务 ,提前编写好通用的模块,需要的地方直接调用
- 比如重复提交判断逻辑
- 类型
- @Before前置通知
- 在执行目标方法之前运行
- @After后置通知
- 在目标方法运行结束之后
- @AfterReturning返回通知
- 在目标方法正常返回值后运行
- @AfterThrowing异常通知
- 在目标方法出现异常后运行
- @Around环绕通知
- 在目标方法完成前、后做增强处理 ,环绕通知是最重要的通知类型 ,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint,需要手动执行 joinPoint.procced()
- @Before前置通知
-
连接点 JointPoint
- 要用通知的地方,业务流程在运行过程中需要插入切面的具体位置,
- 一般是方法的调用前后,全部方法都可以是连接点
- 只是概念,没啥特殊
-
切入点 Pointcut
- 不能全部方法都是连接点,通过特定的规则来筛选连接点, 就是Pointcut,选中那几个你想要的方法
- 在程序中主要体现为书写切入点表达式(通过通配、正则表达式)过滤出特定的一组 JointPoint连接点
- 过滤出相应的 Advice 将要发生的joinpoint地方
-
切面 Aspect
- 通常是一个类,里面定义 切入点+通知 , 定义在什么地方; 什么时间点、做什么事情
- 通知 advice指明了时间和做的事情(前置、后置等)
- 切入点 pointcut 指定在什么地方干这个事情
- web接口设计中,web层->网关层->服务层->数据层,每一层之间也是一个切面,对象和对象,方法和方法之间都是一个个切面
-
目标 target
- 目标类,真正的业务逻辑,可以在目标类不知情的条件下,增加新的功能到目标类的链路上
-
织入 Weaving
- 把切面(某个类)应用到目标函数的过程称为织入
-
第5集 订单防重提交-自定义注解-Token方式效果验证
简介:订单防重提交-自定义注解开发-Token式效果验证
- 下单接口增加注解
@RepeatSubmit(limitType = RepeatSubmit.Type.TOKEN)
- 获取令牌
- 其他bug修复
第6集 订单防重提交-自定义注解开发实战-参数式
简介:订单防重提交-自定义注解开发实战
- 开发配置
//方式一方法参数
long lockTime = noRepeatSubmit.lockTime();
String ip = CommonUtil.getIpAddr(request);
//获取注解
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//目标类、方法
String className = method.getDeclaringClass().getName();
String name = method.getName();
String key = String.format("%s#%s#%s#%s",accountNo,ip, className, name);
log.info("key={}", key);
// 分布式锁 TODO, 直接设置key配置过期时间也行
- 分布式锁几种实现
- Redis+Lua脚本
- Redission
- 直接redis操作
使用原子命令:设置和配置过期时间 setnx / setex
如: set key 1 ex 30 nx
java代码里面
redisTemplate.opsForValue().setIfAbsent(key,1,30,TimeUnit.MILLISECONDS)
第7集 Redission分布式锁介绍和配置引入
简介:Redission分布式锁介绍和配置引入
- Redission介绍
- 是一个在Redis的基础上实现的Java驻内存数据网格,支持多样Redis配置支持、丰富连接方式、分布式对象、分布式集合、分布式锁、分布式服务、多种序列化方式、三方框架整合
- Redisson底层采用的是Netty 框架
- 官方文档:https://github.com/redisson/redisson
- 配置加入
聚合工程锁定版本,common项目添加依赖(多个服务都会用到分布式锁)
<!--分布式锁-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.10.1</version>
</dependency>
- 代码配置
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private String redisPort;
@Value("${spring.redis.password}")
private String redisPwd;
/**
* 配置分布式锁的redisson
* @return
*/
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
//单机方式
config.useSingleServer().setPassword(redisPwd).setAddress("redis://"+redisHost+":"+redisPort);
//集群
//config.useClusterServers().addNodeAddress("redis://192.31.21.1:6379","redis://192.31.21.2:6379")
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
/**
* 集群模式
* 备注:可以用"rediss://"来启用SSL连接
*/
/*@Bean
public RedissonClient redissonClusterClient() {
Config config = new Config();
config.useClusterServers().setScanInterval(2000) // 集群状态扫描间隔时间,单位是毫秒
.addNodeAddress("redis://127.0.0.1:7000")
.addNodeAddress("redis://127.0.0.1:7002");
RedissonClient redisson = Redisson.create(config);
return redisson;
}*/
- 加锁调用
// 分布式锁
RLock lock = redissonClient.getLock(key);
// 尝试加锁,最多等待2秒,上锁以后5秒自动解锁 [lockTime默认为5s, 可以自定义]
res = lock.tryLock(2, lockTime, TimeUnit.SECONDS);
第8集 订单防重提交-自定义注解开发-参数式效果验证
简介:订单防重提交-自定义注解开发-参数式效果验证
-
效果验证
-
两种防重提交,应用场景不一样,也可以更多方式进行防重
-
个人接入微信支付V3版参数示例
- 公众号:appid: wx5beac15ca207c40c
- 商户平台
- 商户号:1601644442
- APIv3密钥:peYcTwRF581UOdaUqoPOeHzJ8FgHgsnJ
- 证书序列号:7064ADC5FE84CA2A3DDE71A692E39602DEB96E61
- 证书文件:本章本集的资料里面(不可用,最新的群公告获取)
Config config = new Config();
config.useClusterServers().setScanInterval(2000) // 集群状态扫描间隔时间,单位是毫秒
.addNodeAddress(“redis://127.0.0.1:7000”)
.addNodeAddress(“redis://127.0.0.1:7002”);
RedissonClient redisson = Redisson.create(config);
return redisson;
}*/
- 加锁调用
```java
// 分布式锁
RLock lock = redissonClient.getLock(key);
// 尝试加锁,最多等待2秒,上锁以后5秒自动解锁 [lockTime默认为5s, 可以自定义]
res = lock.tryLock(2, lockTime, TimeUnit.SECONDS);
第8集 订单防重提交-自定义注解开发-参数式效果验证
简介:订单防重提交-自定义注解开发-参数式效果验证
-
效果验证
-
两种防重提交,应用场景不一样,也可以更多方式进行防重
-
个人接入微信支付V3版参数示例
- 公众号:appid:
- 商户平台
- 商户号:
- APIv3密钥:
- 证书序列号:
- 证书文件:本章本集的资料里面(不可用,最新的群公告获取)