当前位置: 首页 > news >正文

【SpringBoot应用篇】SpringBoot+Redis实现接口幂等性校验

【SpringBoot应用篇】SpringBoot+Redis实现接口幂等性校验

  • 幂等性
  • 解决方法
    • Pom
    • token令牌
      • yml
      • @ApiIdempotentAnn
      • ApiIdempotentInterceptor
      • MVC配置类
      • ApiController
    • 分布式锁 Redisson
      • pom
      • @RedissonLockAnnotation
      • DistributeLocker
      • RedissonDistributeLocker
      • RedissonLockUtils
      • RedissonConfig
      • RedissonLockAop
      • ResultVO
      • BusiController

幂等性

幂等性的定义是:一次和屡次请求某一个资源对于资源自己应该具备一样的结果(网络超时等问题除外)。也就是说,其任意屡次执行对资源自己所产生的影响均与一次执行的影响相同。

WEB系统中: 就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生不同的结果。

什么状况下须要保证幂等性
以SQL为例,有下面三种场景,只有第三种场景须要开发人员使用其余策略保证幂等性:
SELECT col1 FROM tab1 WHER col2=2,不管执行多少次都不会改变状态,是自然的幂等。
UPDATE tab1 SET col1=1 WHERE col2=2,不管执行成功多少次状态都是一致的,所以也是幂等操做。
UPDATE tab1 SET col1=col1+1 WHERE col2=2,每次执行的结果都会发生变化,这种不是幂等的。

解决方法

这里主要使用token令牌分布式锁解决

Pom

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.2.RELEASE</version><relativePath/>
</parent>
<dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.4</version><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- springboot 对aop的支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- springboot mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency>
</dependencies>

token令牌

这种方式分红两个阶段:
1、客户端向系统发起一次申请token的请求,服务器系统生成token令牌,将token保存到Redis缓存中,并返回前端(令牌生成方式可以使用JWT)
2、客户端拿着申请到的token发起请求(放到请求头中),后台系统会在拦截器中检查handler是否开启幂等性校验。取请求头中的token,判断Redis中是否存在该token,若是存在,表示第一次发起支付请求,删除缓存中token后开始业务逻辑处理;若是缓存中不存在,表示非法请求。

yml

spring:redis:host: 127.0.0.1timeout: 5000msport: 6379database: 0datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/study_db?serverTimezone=GMT%2B8&allowMultiQueries=trueusername: rootpassword: root
redisson:timeout: 10000

@ApiIdempotentAnn

@ApiIdempotentAnn幂等性注解。说明: 添加了该注解的接口要实现幂等性验证

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiIdempotentAnn {boolean value() default true;
}

ApiIdempotentInterceptor

这里可以使用拦截器或者使用AOP的方式实现。

幂等性拦截器的方式实现

@Component
public class ApiIdempotentInterceptor extends HandlerInterceptorAdapter {@Autowiredprivate StringRedisTemplate redisTemplate;/*** 前置拦截器*在方法被调用前执行。在该方法中可以做类似校验的功能。如果返回true,则继续调用下一个拦截器。如果返回false,则中断执行,* 也就是说我们想调用的方法 不会被执行,但是你可以修改response为你想要的响应。*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//如果hanler不是和HandlerMethod类型,则返回trueif (!(handler instanceof HandlerMethod)) {return true;}//转化类型final HandlerMethod handlerMethod = (HandlerMethod) handler;//获取方法类final Method method = handlerMethod.getMethod();// 判断当前method中是否有这个注解boolean methodAnn = method.isAnnotationPresent(ApiIdempotentAnn.class);//如果有幂等性注解if (methodAnn && method.getAnnotation(ApiIdempotentAnn.class).value()) {// 需要实现接口幂等性//检查token//1.获取请求的接口方法boolean result = checkToken(request);//如果token有值,说明是第一次调用if (result) {//则放行return super.preHandle(request, response, handler);} else {//如果token没有值,则表示不是第一次调用,是重复调用response.setContentType("application/json; charset=utf-8");PrintWriter writer = response.getWriter();writer.print("重复调用");writer.close();response.flushBuffer();return false;}}//否则没有该自定义幂等性注解,则放行return super.preHandle(request, response, handler);}//检查tokenprivate boolean checkToken(HttpServletRequest request) {//从请求头对象中获取tokenString token = request.getHeader("token");//如果不存在,则返回false,说明是重复调用if(StringUtils.isBlank(token)){return false;}//否则就是存在,存在则把redis里删除tokenreturn redisTemplate.delete(token);}
}

MVC配置类

@Configuration
public class MvcConfig implements WebMvcConfigurer {@Resourceprivate ApiIdempotentInterceptor apiIdempotentInceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(apiIdempotentInceptor).addPathPatterns("/**");}
}

ApiController

@RestController
public class ApiController {@Autowiredprivate StringRedisTemplate stringRedisTemplate;/*** 前端获取token,然后把该token放入请求的header中* @return*/@GetMapping("/getToken")public String getToken() {String token = UUID.randomUUID().toString().substring(1, 9);stringRedisTemplate.opsForValue().set(token, "1");return token;}//定义int类型的原子类的类AtomicInteger num = new AtomicInteger(100);/*** 主业务逻辑,num--,并且加了自定义接口* @return*/@GetMapping("/submit")@ApiIdempotentAnnpublic String submit() {// num--num.decrementAndGet();return "success";}/*** 查看num的值* @return*/@GetMapping("/getNum")public String getNum() {return String.valueOf(num.get());}
}

分布式锁 Redisson

Redisson是redis官网推荐实现分布式锁的一个第三方类库,通过开启另一个服务,后台进程定时检查持有锁的线程是否继续持有锁了,是将锁的生命周期重置到指定时间,即防止线程释放锁之前过期,所以将锁声明周期通过重置延长)

Redission执行流程如下:(只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下(锁续命周期就是设置的超时时间的三分之一),如果线程还持有锁,就会不断的延长锁key的生存时间。因此,Redis就是使用Redisson解决了锁过期释放,业务没执行完问题。当业务执行完,释放锁后,再关闭守护线程,

pom

<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.13.6</version>
</dependency>

@RedissonLockAnnotation

分布式锁注解

@Target(ElementType.METHOD) //注解在方法
@Retention(RetentionPolicy.RUNTIME)
public @interface RedissonLockAnnotation {/*** 指定组成分布式锁的key,以逗号分隔。* 如:keyParts="name,age",则分布式锁的key为这两个字段value的拼接* key=params.getString("name")+params.getString("age")*/String keyParts();
}

DistributeLocker

分布式锁接口

public interface  DistributeLocker {/*** 加锁* @param lockKey key*/void lock(String lockKey);/*** 释放锁** @param lockKey key*/void unlock(String lockKey);/*** 加锁,设置有效期** @param lockKey key* @param timeout 有效时间,默认时间单位在实现类传入*/void lock(String lockKey, int timeout);/*** 加锁,设置有效期并指定时间单位* @param lockKey key* @param timeout 有效时间* @param unit    时间单位*/void lock(String lockKey, int timeout, TimeUnit unit);/*** 尝试获取锁,获取到则持有该锁返回true,未获取到立即返回false* @param lockKey* @return true-获取锁成功 false-获取锁失败*/boolean tryLock(String lockKey);/*** 尝试获取锁,获取到则持有该锁leaseTime时间.* 若未获取到,在waitTime时间内一直尝试获取,超过watiTime还未获取到则返回false* @param lockKey   key* @param waitTime  尝试获取时间* @param leaseTime 锁持有时间* @param unit      时间单位* @return true-获取锁成功 false-获取锁失败*/boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit)throws InterruptedException;/*** 锁是否被任意一个线程锁持有* @param lockKey* @return true-被锁 false-未被锁*/boolean isLocked(String lockKey);
}

RedissonDistributeLocker

redisson实现分布式锁接口

public class RedissonDistributeLocker implements DistributeLocker {private RedissonClient redissonClient;public RedissonDistributeLocker(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@Overridepublic void lock(String lockKey) {RLock lock = redissonClient.getLock(lockKey);lock.lock();}@Overridepublic void unlock(String lockKey) {RLock lock = redissonClient.getLock(lockKey);lock.unlock();}@Overridepublic void lock(String lockKey, int leaseTime) {RLock lock = redissonClient.getLock(lockKey);lock.lock(leaseTime, TimeUnit.MILLISECONDS);}@Overridepublic void lock(String lockKey, int timeout, TimeUnit unit) {RLock lock = redissonClient.getLock(lockKey);lock.lock(timeout, unit);}@Overridepublic boolean tryLock(String lockKey) {RLock lock = redissonClient.getLock(lockKey);return lock.tryLock();}@Overridepublic boolean tryLock(String lockKey, long waitTime, long leaseTime,TimeUnit unit) throws InterruptedException {RLock lock = redissonClient.getLock(lockKey);return lock.tryLock(waitTime, leaseTime, unit);}@Overridepublic boolean isLocked(String lockKey) {RLock lock = redissonClient.getLock(lockKey);return lock.isLocked();}
}

RedissonLockUtils

redisson锁工具类

public class RedissonLockUtils {private static DistributeLocker locker;public static void setLocker(DistributeLocker locker) {RedissonLockUtils.locker = locker;}public static void lock(String lockKey) {locker.lock(lockKey);}public static void unlock(String lockKey) {locker.unlock(lockKey);}public static void lock(String lockKey, int timeout) {locker.lock(lockKey, timeout);}public static void lock(String lockKey, int timeout, TimeUnit unit) {locker.lock(lockKey, timeout, unit);}public static boolean tryLock(String lockKey) {return locker.tryLock(lockKey);}public static boolean tryLock(String lockKey, long waitTime, long leaseTime,TimeUnit unit) throws InterruptedException {return locker.tryLock(lockKey, waitTime, leaseTime, unit);}public static boolean isLocked(String lockKey) {return locker.isLocked(lockKey);}
}

RedissonConfig

Redisson配置类

@Configuration
public class RedissonConfig {@Autowiredprivate Environment env;/*** Redisson客户端注册* 单机模式*/@Bean(destroyMethod = "shutdown")public RedissonClient createRedissonClient() {Config config = new Config();SingleServerConfig singleServerConfig = config.useSingleServer();singleServerConfig.setAddress("redis://" + env.getProperty("spring.redis.host") + ":" + env.getProperty("spring.redis.port"));singleServerConfig.setTimeout(Integer.valueOf(env.getProperty("redisson.timeout")));return Redisson.create(config);}/*** 分布式锁实例化并交给工具类* @param redissonClient*/@Beanpublic RedissonDistributeLocker redissonLocker(RedissonClient redissonClient) {RedissonDistributeLocker locker = new RedissonDistributeLocker(redissonClient);RedissonLockUtils.setLocker(locker);return locker;}
}

RedissonLockAop

这里可以使用拦截器或者使用AOP的方式实现。

分布式锁AOP切面拦截方式实现

@Aspect
@Component
@Slf4j
public class RedissonLockAop {/*** 切点,拦截被 @RedissonLockAnnotation 修饰的方法*/@Pointcut("@annotation(cn.zysheep.biz.redis.RedissonLockAnnotation)")public void redissonLockPoint() {}@Around("redissonLockPoint()")@ResponseBodypublic ResultVO checkLock(ProceedingJoinPoint pjp) throws Throwable {//当前线程名String threadName = Thread.currentThread().getName();log.info("线程{}------进入分布式锁aop------", threadName);//获取参数列表Object[] objs = pjp.getArgs();//因为只有一个JSON参数,直接取第一个JSONObject param = (JSONObject) objs[0];//获取该注解的实例对象RedissonLockAnnotation annotation = ((MethodSignature) pjp.getSignature()).getMethod().getAnnotation(RedissonLockAnnotation.class);//生成分布式锁key的键名,以逗号分隔String keyParts = annotation.keyParts();StringBuffer keyBuffer = new StringBuffer();if (StringUtils.isEmpty(keyParts)) {log.info("线程{} keyParts设置为空,不加锁", threadName);return (ResultVO) pjp.proceed();} else {//生成分布式锁keyString[] keyPartArray = keyParts.split(",");for (String keyPart : keyPartArray) {keyBuffer.append(param.getString(keyPart));}String key = keyBuffer.toString();log.info("线程{} 要加锁的key={}", threadName, key);//获取锁if (RedissonLockUtils.tryLock(key, 3000, 5000, TimeUnit.MILLISECONDS)) {try {log.info("线程{} 获取锁成功", threadName);// Thread.sleep(5000);return (ResultVO) pjp.proceed();} finally {RedissonLockUtils.unlock(key);log.info("线程{} 释放锁", threadName);}} else {log.info("线程{} 获取锁失败", threadName);return ResultVO.fail();}}}
}

ResultVO

统一响应实体

@Data
public class ResultVO<T> {private static final ResultCode SUCCESS = ResultCode.SUCCESS;private static final ResultCode FAIL = ResultCode.FAILED;private Integer code;private String message;private T  data;public static <T> ResultVO<T> ok() {return result(SUCCESS,null);}public static <T> ResultVO<T> ok(T data) {return result(SUCCESS,data);}public static <T> ResultVO<T> ok(ResultCode resultCode) {return result(resultCode,null);}public static <T> ResultVO<T> ok(ResultCode resultCode, T data) {return result(resultCode,data);}public static <T> ResultVO<T> fail() {return result(FAIL,null);}public static <T> ResultVO<T> fail(ResultCode resultCode) {return result(FAIL,null);}public static <T> ResultVO<T> fail(T data) {return result(FAIL,data);}public static <T> ResultVO<T> fail(ResultCode resultCode, T data) {return result(resultCode,data);}private static <T>  ResultVO<T> result(ResultCode resultCode, T data) {ResultVO<T> resultVO = new ResultVO<>();resultVO.setCode(resultCode.getCode());resultVO.setMessage(resultCode.getMessage());resultVO.setData(data);return resultVO;}
}

BusiController

@RestController
public class ApiController {@PostMapping(value = "testLock")@RedissonLockAnnotation(keyParts = "name,age")public ResultVO testLock(@RequestBody JSONObject params) {/*** 分布式锁key=params.getString("name")+params.getString("age");* 此时name和age均相同的请求不会出现并发问题*///TODO 业务处理dwadreturn ResultVO.ok();}
}

相关文章:

qsettings 读写注册表

qsettings简单的实现一个注册表读写操作&#xff0c;记录程序中需要保存的信息。使用qsettings声明对象之前&#xff0c;需要指明qsettings的组织名和应用名&#xff0c;分别利用QCoreApplication::setOrganizationName()和QCoreApplication::setApplicationName()来指定组织名…...

【JavaScript高级进阶】构造函数和原型,学会prototype

目录 前言 1.构造函数和原型 1.1使用prototype解决内存浪费的问题 1.2constructor构造函数构造器构造函数 2.原型链 2.1js中成员查找规则 2.2原型对象this指向 2.3扩展内置对象 3.call作用 4.继承 4.1利用原型对象继承 写在最后 前言 哈喽哈喽大家好&#xff0c;因为…...

【学生个人网页设计作品】使用HMTL制作一个超好看的保护海豚动物网页

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…...

公众号网课查题系统

公众号网课查题系统 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 查题校园题库&#xff1a;查题校园题库后台&#xff08;点击…...

CodeForces - 545E Paths and Trees 最短路建树

题目链接&#xff1a;点击查看 Little girl Susie accidentally found her elder brothers notebook. She has many things to do, more important than solving problems, but she found this problem too interesting, so she wanted to know its solution and decided to a…...

【工具使用】Visual Studio Code远程调试

VS Code的其中一个关键的特征就是它极好的调试支持。VS Code的内置调试器帮助加速你的编辑、编译和调试循环。 调试扩展 VS Code有Node.js运行的内置的调试支持&#xff0c;并且能够调试Java脚本或者任何其他可以转译为JavaScript的语言。为了调试其他语言&#xff08;包括P…...

ADB学习笔记

简介&#xff1a; ADB的全称为Android Debug Bridge&#xff08;调试桥&#xff09;&#xff0c; 它是一个客户端-服务器端程序&#xff0c;其中客户端是你用来操作的电脑, 服务器端是android设备。作用显而易见&#xff0c;能方便我们在PC上对手机进行调试的一些工作。 原理…...

http load介绍

前几天工作中要对项目的接口做简单压测&#xff0c;就使用了http load做了简单测试&#xff0c;下面介绍一下这款工具的使用说明。简介&#xff1a;http_load是基于linux平台的性能测试工具&#xff0c;它体积非常小&#xff0c;仅100KB。它以并行复用的方式运行&#xff0c;可…...

Linux shell脚本之回顾及实用笔记

一、前言 我们从事运维的小伙伴,除了自动化运维外,在没有自动化条件下,借助shell脚本/Python脚本来提升运维效率,无疑是一个必选项,当前也可以自建自动化运维平台,我们这里还是以Linux shell脚本为主,来汇总一些常用的运维脚本,对于有基础的同学,也随本文一起回顾下相…...

TestNG使用总结

TestNG简介&#xff1a; TestNG是一个测试框架&#xff0c;其灵感来自JUnit和NUnit&#xff0c;但同时引入了一些新的功能&#xff0c;使其功能更强大&#xff0c;使用更方便。 TestNG相较于Junit的优点&#xff1a; 可指定执行顺序&#xff0c; dependsOnMethods 属性来应对…...

面向对象编程的弊端

英文原文&#xff1a;What’s Wrong with OOP and FP 我不理解为什么人们会对面向对象编程和函数式编程做无休无止的争论。就好象这类问题已经超越了人类智力极限&#xff0c;所以你可以几个世纪的这样讨论下去。经过这些年对编程语言的研究&#xff0c;我已经清楚的看到了问题…...

flex 计算指定日期是本年度第几周

/** * 计算指定日期是本年度第几周 *传日年月日&#xff0c;返回number */ private function weekOfYear(yyyy:Number,mm:Number,dd:Number):Number{ var myDate:Date new Date(yyyy, mm - 1, dd); var startDate:Date new Date(yyyy,0,1); v…...

SpringCloud Zuul(四)之工作原理

一、筛选器概述 Zuul的中心是一系列过滤器&#xff0c;这些过滤器能够在HTTP请求和响应的路由期间执行一系列操作。 以下是Zuul过滤器的主要特征&#xff1a; 类型&#xff1a;通常定义路由流程中应用过滤器的阶段&#xff08;尽管它可以是任何自定义字符串&#xff09;执行…...

[CSS]圆角边框与阴影

前言 系列文章目录&#xff1a; [目录]HTML CSS JS 根据视频和PPT整理视频及对应资料&#xff1a;HTML CSS 老师笔记&#xff1a; https://gitee.com/xiaoqiang001/html_css_material.git视频&#xff1a;黑马程序员pink老师前端入门教程&#xff0c;零基础必看的h5(html5)css3…...

Neo4j 开发者大会 NODES 2022 活动日程已发布 - 11.16 ~ 11.17

各位 Graphistas&#xff1a; Neo4j 开发者大会 NODES 2022 将在 2022 年 11 月 16&#xff5e;17 日召开&#xff0c;不要错过这连续 24 小时跨越 3 个主要时区的大型在线活动&#xff0c;欢迎加入我们一起庆祝来自全球图技术社区的隆重分享。 现在访问官方网站注册活动: ht…...

Google Swift 与 DC 传输

网络拥塞&#xff0c;默认指转发节点出现了严重的排队现象&#xff0c;甚至队列溢出而丢包。、 但接收端也是一个统计复用系统(通用 OS 均为统计复用系统&#xff0c;比如 Linux)&#xff0c;但凡统计复用系统就是潜在拥塞点&#xff0c;即可套用排队论模型。 人们很少将最后…...

webservice学习记录笔记(一)

一、先理解什么是服务 现在的应用程序变得越来越复杂&#xff0c;甚至只靠单一的应用程序无法完成全部的工作。更别说只使用一种语言了。 写应用程序查询数据库时&#xff0c;并没有考虑过为什么可以将查询结果返回给上层的应用程序&#xff0c;甚至认为&#xff0c;这就是数…...

spring Cloud微服务 security+oauth2认证授权中心自定义令牌增强,并实现登录和退出

文章目录认证授权中心自定义令牌增强自定义认证端点返回结果登录逻辑调整&#xff0c;增强令牌返回参数测试验证用户微服务构建配置类构建相关实体类登录退出登录在之前的博客我写了 SpringCloud整合spring security oauth2Redis实现认证授权&#xff0c;本文对返回的token实现…...

接口测试那些事儿

什么是接口&#xff1f; 首先&#xff0c;在讲接口测试之前&#xff0c;我们先要搞清楚接口类型的概念。 接口&#xff1a;可能是系统与系统&#xff08;包括服务与服务&#xff09;之间的调用&#xff0c;像A系统&#xff08;服务&#xff09;给B系统&#xff08;服务&#x…...

CodeForces - 1084C The Fair Nut and String 思维

The Fair Nut found a string s. The string consists of lowercase Latin letters. The Nut is a curious guy, so he wants to find the number of strictly increasing sequences p1,p2,…,pk , such that: For each i (1≤i≤k), spi a.For each i(1≤i<k), there is…...

【晶振专题】案例:为什么对着STM32低速32.768K晶振哈口气就不起振了?

本案例发现在一个工装产品上,首批一共做了10几台样机。发现有的样机在开机的时候读取不到RTC,有的样机却可以。读不到RTC是概率性出现的,发生在第一次上电的情况。开始他怀疑是环境问题,会不会和温度有关,于是同事在家做了大量的实验,发现对晶振吹口气就能让晶振不起振,…...

Gym - 101986B Parallel Lines dfs暴力

链接&#xff1a;点击查看 题意&#xff1a;偶数个点&#xff0c;两点可连成一条线&#xff0c;求平行线最大对数 题解&#xff1a;当时想的时候傻逼了&#xff0c;想成了每次选两个点就是16*15/2 * 14*13/2 ..... 其实不需要这样&#xff0c;因为每个点必须要匹配一个的&…...

Keychron Q1:客制化机械键盘|体验

在Cherry轴垄断的后几年&#xff0c;国产机械轴一举反超&#xff0c;在性价比、手感、耐用性上实现了全面碾压。至少现在的键圈和智能手机一样&#xff0c;支持国货不仅是情怀&#xff0c;更是为产品力在买单。 至于“如何卷”键盘的玩法可比智能手机多得去了&#xff0c;可能…...

POJ - 2406 Power Strings next数组应用循环节

题目链接&#xff1a;点击查看 Language:Default Power Strings Time Limit: 3000MS Memory Limit: 65536KTotal Submissions: 61784 Accepted: 25534Description Given two strings a and b we define a*b to be their concatenation. For example, if a "abc" and…...

CodeForces - 545D Queue 贪心 排序

题目链接&#xff1a;点击查看 Little girl Susie went shopping with her mom and she wondered how to improve service quality. There are n people in the queue. For each person we know time ti needed to serve him. A person will be disappointed if the time he …...

Jmeter访问HTTPS请求

公司最近在搞全站HTTPS改造&#xff0c;进一步提高网站的安全性&#xff0c;防止运营商劫持。那么&#xff0c;改造完成后&#xff0c;所有前后端的URL将全部为https。 So &#xff0c;研究下怎么用Jmeter访问https请求呢。 其实很简单&#xff0c; 第一步在jmeter中创建HTT…...

python导入安装包

主要分两种方式&#xff1a;在线安装和离线安装 在线安装 因为我公司开发是在云桌面&#xff0c;里面是没有外网的。之前是只能离线安装&#xff0c;后面搭了一个内部镜像环境。 1.添加配置文件进行换源 2.检查requirements.txt配置 3.直接使用pycahrm工具install 换源 …...

HDU - 6188 Duizi and Shunzi 贪心

Nike likes playing cards and makes a problem of it. Now give you n integers, ai(1≤i≤n) We define two identical numbers (eg: 2,2) a Duizi, and three consecutive positive integers (eg: 2,3,4) a Shunzi. Now you want to use these integers to form Shunzi and …...

JSON相关知识点

JSON是工作中经常会遇到的一种数据结构&#xff0c;下面来讲讲与他相关的一些知识点。 JSON简介&#xff1a; JSON: JavaScript Object Notation(JavaScript 对象表示法) JSON 是存储和交换文本信息的语法,类似 XML。 JSON 比 XML 更小、更快&#xff0c;更易解析。 JSONObj…...

每天五分钟机器学习:超平面分离定理和凸优化

凸集和凸函数 在点集拓扑学与欧几里得空间中,凸集是一个点集,其中每两点之间的直线上的点都落在该点集中。如下所示: 函数任意两点(x,f(x))和(y,f(y))连线上的值大于(x,y)区间内任意一点m的值f(m),那么这个函数就是一个凸函数: 超平面分离定理 空间中存在两类样本,…...

目标检测(6)—— YOLO系列V2

一、YOLOV2改进的概述 做的改进如下图&#xff1a; Batch Normalization 批量归一化层 不加BN层&#xff0c;网络可能学偏&#xff0c;加上归一化进行限制。 从今天来看&#xff0c;conv后加BN是标配。 更大的分辨率 V1训练的时候使用224224&#xff0c;测试用448448。 V2训…...

数据中心典型测试场景浅析

数据中心概述 数据中心泛指拥有众多服务器的大型机房&#xff0c;通过利用通信运营商已有的互联网通信线路、带宽资源&#xff0c;建立标准化的数据中心机房环境&#xff0c;具有运行速度快、存储量大、安全性高等特点。数据中心东西向流量的占比更大&#xff0c;传统的园区网…...

2022学年第一学期郑州大学ACM招新赛选拔赛

A SW的与众不同数组 — 签到 一共n个数&#xff0c; 用set无重复值的性质统计一下有几个不同的数&#xff0c;记为 res n - res 如果是偶数 每次删除两个刚好可以&#xff0c;如果是奇数需要再删除一个不重复的数完成对应操作 #include <iostream> #include <set>…...

牛客网 Applese 走方格

题目链接&#xff1a;点击查看 题解&#xff1a;我们容易发现到当n,m都为奇数时&#xff0c;是回不到原点的&#xff0c;因为你无论哪个方向走一去一回就是两步&#xff0c;所以n和m必然有一个偶数&#xff0c;那至于我们怎么走呢&#xff0c;看下图&#xff0c;注意的是n1,m2…...

mysql重置Root密码

方法一: 在my.ini的[mysqld]字段加入&#xff1a; skip-grant-tables 重启mysql服务&#xff0c;这时的mysql不需要密码即可登录数据库 然后进入mysql mysql>use mysql; mysql>更新 user set passwordpassword(新密码) WHERE Userroot; mysql>flush privileges; 运…...

胡扯推荐算法(协同)及其dome实现

文章目录前言推荐系统定义基本分类相似度计算欧式距离皮尔逊系数余弦相似度协同过滤案例数据定义相似度计算推荐svd奇异值分解优化完整代码总结前言 打瞌睡遇到送枕头的感觉真爽嘿嘿 BoyC啊 废话不多说&#xff0c;开始吧。 推荐系统定义 推荐系统(Recommendation System,…...

C · 初阶 | 循环语句

啊我摔倒了..有没有人扶我起来学习.... &#x1f471;个人主页&#xff1a;《CGod的个人主页》\color{Darkorange}{《CGod的个人主页》}《CGod的个人主页》交个朋友叭~ &#x1f492;个人社区&#xff1a;《编程成神技术交流社区》\color{Darkorange}{《编程成神技术交流社区》…...

idea常用技巧收集

idea相比eclipse的优点我在这里就不赘述了&#xff0c;更多参考&#xff1a;idea官网,本文重点讲下自己在idea使用过程中常用的一些技巧&#xff0c;以后随时更新…… 主要分成三大块&#xff1a; 1. 系统设置 2. 快捷键 3. 其他设置 系统设置 主题风格设置&#xff1a;默…...

深入理解spark高阶算子combineByKey

今天来详细说说spark中的一个比较底层的算子combineByKey。 熟悉spark的朋友应该知道&#xff0c;spark里面有很多类型的算子&#xff0c;有些比较基础&#xff0c;什么map&#xff0c;filter&#xff0c;可能看一眼就会了&#xff0c;有些稍微复杂点&#xff0c;但是也不难懂…...

架构设计 例子和实践 系统设计说明书

架构设计 例子和实践 系统设计说明书(架构、概要、详细)目录结构演进架构中的领域驱动设计Web架构设计经验分享软件架构设计从MVC框架看MVC架构的设计领域驱动设计(Domain Driven Design)参考架构详解关于垂直切分Vertical Sharding的粒度企业应用集成与开源ESB产品ServiceMix和…...

想要玩转实现负载均衡,你知道这些吗?

转载自 想要玩转实现负载均衡&#xff0c;你知道这些吗&#xff1f; 一、前言 互联网早期&#xff0c;业务流量比较小并且业务逻辑比较简单&#xff0c;单台服务器便可以满足基本的需求&#xff1b;但随着互联网的发展&#xff0c;业务流量越来越大并且业务逻辑也越来越复杂&…...

算法 - 里程表故障

题目描述 You are given a car odometer which displays the miles traveled as an integer. The odometer has a defect, however: it proceeds from the digit 2 to the digit 4 and from the digit 7 to the digit 9, always skipping over the digit 3 and 8. This defect…...

初识spring RestTemplate

《spring实战》读书笔记之初识spring RestTemplate。首先需要先了解下什么是REST。 REST&#xff1a;官方解释&#xff0c;表述性状态转移。 感觉还是不知所云&#xff0c;参考下怎样用通俗的语言解释REST&#xff0c;以及RESTful&#xff1f; 即URL定位资源&#xff0c;用H…...

程序员着装的改变

是什么力量&#xff0c;让任何地方的程序员都享有「免于体面的自由」&#xff1f; 在今天的社会里&#xff0c;工程师往往代表着知识水平和社会地位。每当普通人听到这个头衔&#xff0c;总会报之以敬仰的目光&#xff1a; 但有一种工程师&#xff0c;虽然也是如假包换的高级技…...

Simulink仿真中将工作空间中的数据变量保存成.mat文件

在基于模型开发的过程当中&#xff0c;除了模型本身之外&#xff0c;模型的参数也是开发成果的一个重要部分&#xff0c;为了下次仿真能够更快的运用参数&#xff0c;在本次仿真中可以将经常需要的参数保存&#xff0c;以便于下次仿真使用。 一般常用的有两种方法&#xff1a;…...

谈谈系统稳定性设计

转载自 谈谈系统稳定性设计 一、差旅随想 因为base在分公司&#xff0c;需要经常去总部出差&#xff0c;所以搭乘飞机成了家常便饭&#xff0c;很多时候坐在飞机上会不由的感叹&#xff0c;设计制造这样精密复杂的机器的那帮人真的是了不起&#xff0c;他们是怎样保证这样一台…...

内网渗透 Metasploit(MSF)基础使用

内网渗透 Metasploit&#xff08;MSF&#xff09;使用 1、认识 MSF ​ Metasploit 是一款开源的安全漏洞检测工具&#xff0c;可以帮助安全和IT专业人士识别安全性问题&#xff0c;验证漏洞的缓解措施&#xff0c;并管理专家驱动的安全性进行评估&#xff0c;提供真正的安全风…...

【论文阅读】EDPLVO: Efficient Direct Point-Line Visual Odometry

一、公式及符号约定 这篇论文是将直接法的残差计算从点扩展到了线段&#xff0c;所以一些符号在第三章的部分提前做了约定。用Π表示投影的函数&#xff0c;也就是用像素坐标和内参矩阵以及深度信息&#xff0c;投影出点的空间坐标&#xff0c;反之Π-1表示的是将空间坐标投影…...

数据结构—笔记整理—初识数据结构

学习之路&#xff0c;长路漫漫&#xff0c;写学习笔记的过程就是把知识讲给自己听的过程。 目录 数据结构初定义 常用数据结构 这 8 种数据结构有什么区别呢&#xff1f; ①、数组 ②、链表 ③、栈 ④、队列 ⑤、树 ⑥、堆 ⑦、图 ⑧、哈希表 数据结构 集合结构(非…...

抖音10月的带货风向是什么?

站内大促氛围火爆&#xff0c;双十一好物节加持下&#xff0c;又有哪些亮眼主播、热卖商品和出圈品牌呢&#xff1f;通过新抖统计的10月1日-10月31日的月榜数据&#xff0c;一起来了解看看吧。01 30主播带货破亿 东方甄选蝉联榜首据新抖「主播带货榜」数据显示&#xff0c;10月…...