Spring Boot接口请求响应慢,超过10秒以上,如无法优化SQL或代码的情况下,建议写入数据库或缓存中,请求接口时从数据库或缓存中读取返回

news2024/11/16 12:24:03

举例

@Override
public Map<String, Object> getCockpitStaffAttendanceTask() {

	Map<String, Object> map = new HashMap<>();

	int chuqin = 0; //出勤
	int queqin = 0; //缺勤
	int chidao = 0; //迟到
	int zaotui = 0; //早退

	//获取所有设备卡号 并且已经绑定了人
	List<CardDeviceInfo> cardDeviceInfoList = cardDeviceInfoService.list(new LambdaQueryWrapper<CardDeviceInfo>().isNotNull(CardDeviceInfo::getStaffId).eq(CardDeviceInfo::getCardStatus,0));
	for (CardDeviceInfo cardDeviceInfo : cardDeviceInfoList) {
		if (StringUtils.isNotEmpty(cardDeviceInfo.getLandId()) && StringUtils.isNotEmpty(cardDeviceInfo.getJobTimeId())){
			//判断当天是否有轨迹
			CardDeviceTrajectoryInfo cardDeviceTrajectoryInfosToDay = sanitationJobStatisticsMapper.selectToDayTrajectory(cardDeviceInfo.getImei());
			if (ObjectUtils.isNotEmpty(cardDeviceTrajectoryInfosToDay)){
				chuqin += 1;
			}else{
				queqin += 1;
			}
			//先处理作业地块和作业时间
			String landId = cardDeviceInfo.getLandId();
			String[] jobTypeSplit = cardDeviceInfo.getJobTimeId().split(",");
			List<String> jobTypeStartTimeList = new ArrayList<>();
			List<String> jobTypeEndTimeList = new ArrayList<>();

			List<String> geomList = sanitationJobStatisticsMapper.getGeomByLandId(Integer.parseInt(landId));
			for (String jobTypeId : jobTypeSplit) {
				// (防止多个时间段)根据作业类型编号 获取 作业时间段的开始时间以及结束时间 xml中使用forEach提取
				List<SanitationRoadOperationTimeInfo> list = sanitationRoadOperationTimeInfoService.lambdaQuery().eq(SanitationRoadOperationTimeInfo::getPid, Integer.parseInt(jobTypeId)).list();
				list.forEach(l -> {
					jobTypeStartTimeList.add(l.getStartTime().toString());
					jobTypeEndTimeList.add(l.getEndTime().toString());
				});
			}

			//获取最早的一条
			CardDeviceTrajectoryInfo chuQinTrajectory = sanitationJobStatisticsMapper.getChuQinCdTrajectory(cardDeviceInfo.getImei(), geomList);
			//获取最晚的一条
			CardDeviceTrajectoryInfo chuQinTrajectoryDesc = sanitationJobStatisticsMapper.getChuQinTrajectoryDesc(cardDeviceInfo.getImei(), geomList);
			//判断是否迟到
			if (ObjectUtils.isNotEmpty(chuQinTrajectory)){
				Boolean ifChiDao = sanitationJobStatisticsMapper.ifChiDao(chuQinTrajectory.getGpsTime(), jobTypeStartTimeList);
				if (ifChiDao){
					chidao += 1;
				}
			}

			//如果时间到达晚上17点30 则统计是否有早退人员
			LocalTime now = LocalTime.now(); // 获取当前时间
			if (now.isAfter(LocalTime.of(17, 30))) {
				CardDeviceTrajectoryInfo chuQinTrajectoryZt = sanitationJobStatisticsMapper.getChuQinZtTrajectory(cardDeviceInfo.getImei(), geomList);
				//判断是否早退
				if (ObjectUtils.isNotEmpty(chuQinTrajectoryZt)){
					Boolean ifZaoTui = sanitationJobStatisticsMapper.ifZaoTui(chuQinTrajectoryDesc.getGpsTime(), jobTypeEndTimeList);
					if (ifZaoTui){
						zaotui += 1;
					}
				}
			}
		}
	}

	map.put("chuqin",chuqin);
	map.put("queqin",queqin);
	map.put("chidao",chidao);
	map.put("zaotui",zaotui);

	return map;
}

查询消耗了38秒左右

在这里插入图片描述

1、定时写入数据库,从数据库中读取

如果数据量较大,字段较多,需要存储历史记录,则存入数据库会好些,存入数据库就是基本的insert语句,接口直接调用select查询出来就行了!

2、定时写入Redis缓存、从缓存中读取

如果数据量较少,字段较少,不需要存储历史记录的,可以直接存到Redis缓存里,接口需要的时候直接从Redis中取出即可!

package com.yutu.garden.task;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.yutu.garden.entity.CardDeviceInfo;
import com.yutu.garden.entity.CardDeviceTrajectoryInfo;
import com.yutu.garden.entity.SanitationRoadOperationTimeInfo;
import com.yutu.garden.mapper.gardens.SanitationJobStatisticsMapper;
import com.yutu.garden.service.CardDeviceInfoService;
import com.yutu.garden.service.SanitationRoadOperationTimeInfoService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

@Component
@EnableScheduling
//@ConditionalOnProperty(name = "scheduled.tasks.enabled", havingValue = "true")
@EnableAsync
public class CockpitStaffAttendanceTask {
	@Autowired
	private RedisTemplate<String, Object> redisTemplate;
	@Resource
	private CardDeviceInfoService cardDeviceInfoService;
	@Resource
	private SanitationJobStatisticsMapper sanitationJobStatisticsMapper;
	@Resource
	private SanitationRoadOperationTimeInfoService sanitationRoadOperationTimeInfoService;

	//缓存到Redis中
	//每5分钟执行一次
	@Scheduled(cron = "0 */5 * * * ?")
	public void cockpitStaffAttendanceTask() {

		int chuqin = 0; //出勤
		int queqin = 0; //缺勤
		int chidao = 0; //迟到
		int zaotui = 0; //早退

		//获取所有设备卡号 并且已经绑定了人
		List<CardDeviceInfo> cardDeviceInfoList = cardDeviceInfoService.list(new LambdaQueryWrapper<CardDeviceInfo>().isNotNull(CardDeviceInfo::getStaffId).eq(CardDeviceInfo::getCardStatus,0));
		for (CardDeviceInfo cardDeviceInfo : cardDeviceInfoList) {
			if (StringUtils.isNotEmpty(cardDeviceInfo.getLandId()) && StringUtils.isNotEmpty(cardDeviceInfo.getJobTimeId())){
				//判断当天是否有轨迹
				CardDeviceTrajectoryInfo cardDeviceTrajectoryInfosToDay = sanitationJobStatisticsMapper.selectToDayTrajectory(cardDeviceInfo.getImei());
				if (ObjectUtils.isNotEmpty(cardDeviceTrajectoryInfosToDay)){
					chuqin += 1;
				}else{
					queqin += 1;
				}
				//先处理作业地块和作业时间
				String landId = cardDeviceInfo.getLandId();
				String[] jobTypeSplit = cardDeviceInfo.getJobTimeId().split(",");
				List<String> jobTypeStartTimeList = new ArrayList<>();
				List<String> jobTypeEndTimeList = new ArrayList<>();

				List<String> geomList = sanitationJobStatisticsMapper.getGeomByLandId(Integer.parseInt(landId));
				for (String jobTypeId : jobTypeSplit) {
					// (防止多个时间段)根据作业类型编号 获取 作业时间段的开始时间以及结束时间 xml中使用forEach提取
					List<SanitationRoadOperationTimeInfo> list = sanitationRoadOperationTimeInfoService.lambdaQuery().eq(SanitationRoadOperationTimeInfo::getPid, Integer.parseInt(jobTypeId)).list();
					list.forEach(l -> {
						jobTypeStartTimeList.add(l.getStartTime().toString());
						jobTypeEndTimeList.add(l.getEndTime().toString());
					});
				}

				//获取最早的一条
				CardDeviceTrajectoryInfo chuQinTrajectory = sanitationJobStatisticsMapper.getChuQinCdTrajectory(cardDeviceInfo.getImei(), geomList);
				//获取最晚的一条
				CardDeviceTrajectoryInfo chuQinTrajectoryDesc = sanitationJobStatisticsMapper.getChuQinTrajectoryDesc(cardDeviceInfo.getImei(), geomList);
				//判断是否迟到
				if (ObjectUtils.isNotEmpty(chuQinTrajectory)){
					Boolean ifChiDao = sanitationJobStatisticsMapper.ifChiDao(chuQinTrajectory.getGpsTime(), jobTypeStartTimeList);
					if (ifChiDao){
						chidao += 1;
					}
				}

				//如果时间到达晚上17点30 则统计是否有早退人员
				LocalTime now = LocalTime.now(); // 获取当前时间
				if (now.isAfter(LocalTime.of(17, 30))) {
					CardDeviceTrajectoryInfo chuQinTrajectoryZt = sanitationJobStatisticsMapper.getChuQinZtTrajectory(cardDeviceInfo.getImei(), geomList);
					//判断是否早退
					if (ObjectUtils.isNotEmpty(chuQinTrajectoryZt)){
						Boolean ifZaoTui = sanitationJobStatisticsMapper.ifZaoTui(chuQinTrajectoryDesc.getGpsTime(), jobTypeEndTimeList);
						if (ifZaoTui){
							zaotui += 1;
						}
					}
				}
			}
		}

		redisTemplate.opsForValue().set("schuqin", String.valueOf(chuqin));
		redisTemplate.opsForValue().set("squeqin", String.valueOf(queqin));
		redisTemplate.opsForValue().set("schidao", String.valueOf(chidao));
		redisTemplate.opsForValue().set("szaotui", String.valueOf(zaotui));

	}

	//打印测试
	@Scheduled(cron = "0 */1 * * * ?")
	public void getRedisValue(){
		String chuqin = (String) redisTemplate.opsForValue().get("chuqin");
		String queqin = (String) redisTemplate.opsForValue().get("queqin");
		String chidao = (String) redisTemplate.opsForValue().get("chidao");
		String zaotui = (String) redisTemplate.opsForValue().get("zaotui");

		System.out.println("打印出勤:"+chuqin);
		System.out.println("打印缺勤:"+queqin);
		System.out.println("打印迟到:"+chidao);
		System.out.println("打印早退:"+zaotui);
	}
}

不到1秒,从Redis中提取
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1386885.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis之bigkey

目录 1、什么是bigkey&#xff1f; 2、bigkey大的小 3、bigkey有哪些危害&#xff1f; 4、bigkey如何产生&#xff1f; 5、bigkey如何发现&#xff1f; 6、bigkey如何删除&#xff1f; 7、BigKey调优&#xff0c;惰性释放lazyfree 8、生产上限制keys * /flushdb/flushal…

python爬虫之线程与多进程知识点记录

一、线程 1、概念 线程 在一个进程的内部&#xff0c;要同时干多件事&#xff0c;就需要同时运行多个“子任务”&#xff0c;我们把进程内的这些“子任务”叫做线程 是操作系统能够进行运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。一条线程指…

统计学-R语言-4.1

文章目录 前言编写R函数图形的控制和布局par函数layout函数 练习 前言 安装完R软件之后就可以对其进行代码的编写了。 编写R函数 如果对数据分析有些特殊需要&#xff0c;已有的R包或函数不能满足&#xff0c;可以在R中编写自己的函数。函数的定义格式如下所示&#xff1a; …

DFT新手入门:VASPKIT生成模版INCAR

新手学习VASP计算时一般需要自行准备好VASP所需要的四个输入文件:INCAR POSCAR KPOINTS POTCAR。 其中POSCAR为计算任务的模型文件&#xff0c;POTCAR为与POSCAR中元素所对应的赝势&#xff0c;可根据要求选取。 KPOINTS的设置需要根据精度确定&#xff0c;一般通过vaspkit的1…

鸿蒙开发OpenHarmony组件复用案例

概述 在开发应用时&#xff0c;有些场景下的自定义组件具有相同的组件布局结构&#xff0c;仅有状态变量等承载数据的差异。这样的组件缓存起来&#xff0c;需要使用到该组件时直接复用&#xff0c; 减少重复创建和渲染的时间&#xff0c;从而提高应用页面的加载速度和响应速度…

Win10专业版系统搭建DNS解析服务

Win10专业版 纯新手&#xff0c;也没弄过Linux的。不喜勿喷&#xff0c;有问题请指出 第一天一头雾水整了几个小时没结果&#xff0c;第二天豁然开朗&#xff0c;10分钟明白了第一天的问题所在。 Win10 安卓&#xff1a; iOS&#xff1a; 搭建DNS服务器的意义&#xff1a; 屏蔽…

【Axure高保真原型】移入放大对应区域的饼图

今天和大家分享移入放大对应扇形区域的饼图的原型模板&#xff0c;鼠标移入时&#xff0c;对应扇形区域的会放大&#xff0c;并且的项目和数据弹窗&#xff0c;弹窗可以跟随鼠标移动。这个原型是用Axure原生元件制作的&#xff0c;所以不需要联网或者调用外部图表……具体效果可…

2024年烟花爆竹储存证考试题库及烟花爆竹储存试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年烟花爆竹储存证考试题库及烟花爆竹储存试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大纲随机…

多示例学习 (multi-instance learning, MIL) 学习路线 (归类、重点文章列举、持续更新)

文章目录 0 要点 0 要点 说明&#xff1a;本文在于能够让大家能够更加快速地了解MIL这个领域&#xff0c;因此将从以下几个方面重点介绍MIL&#xff1a; MIL背景介绍&#xff1b;理论MIL概述&#xff1a; 注意力网络&#xff1b;对比学习&#xff1b;介入学习&#xff1b;强化…

sylar高性能服务器-日志(P15-P20)内容记录

以下内容是sylar高性能服务器视频的简单记录&#xff0c;如果你在调试代码时遇到了困难那么下面内容会有帮助。 文章目录 p15&#xff1a;配置变更事件一、函数二、结果展示 p16&#xff1a;日志系统的整合1一、函数二、小结 p17-18&#xff1a;日志系统的整合2、3一、函数二、…

网络命令行工具nc的使用复习

之前写过nc的博文&#xff1b;下面复习一下&#xff1b; 可以把nc放到C:\Windows\System32下&#xff1b; nc -l -p 9007&#xff0c;-l 是监听模式&#xff0c;-p指定端口&#xff0c;作为服务端监听9007端口&#xff1b; nc 127.0.0.1 9007&#xff0c;作为客户端去连接指定…

基于算术电路的全同态加密方案介绍

基于算术电路的全同态加密方案介绍 摘 要&#xff1a; 云计算技术目前已经发展得相对成熟&#xff0c;应用也逐步得到普及&#xff0c;它所具有的强大的数据处理能力&#xff0c;能够帮助个体用户计算复杂的数据。但它带来便利的同时&#xff0c;也催生了一系列用户隐私数据保…

Vue2.组件通信

样式冲突 写在组件中的样式默认会全局生效。容易造成多个组件之间的样式冲突问题。 可以给组件加上scoped属性&#xff0c;让样式只作用于当前组件。 原理&#xff1a; 给当前组件模板的所有元素&#xff0c;加上一个自定义属性data-v-hash值&#xff0c;用以区分不同的组件。…

七大排序(含快排+归并的递归版和非递归版)

文章目录 前言一、冒泡排序二、选择排序三、插入排序四、希尔排序五、堆排序六、快速排序快排的递归方式快排的非递归方式 七、归并排序自上而下的递归自下而上的迭代 总结 前言 排序&#xff1a; 所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的…

二分图带权最大匹配-KM算法详解

文章目录 零、前言一、红娘再牵线二、二分图带权最大完备匹配2.1二分图带权最大匹配2.2概念2.3KM算法2.3.1交错树2.3.2顶标2.3.3相等子图2.3.4算法原理2.3.5算法实现 三、OJ练习3.1奔小康赚大钱3.2Ants 零、前言 关于二分图&#xff1a;二分图及染色法判定-CSDN博客 关于二分…

Vue + JS + tauri 开发一个简单的PC端桌面应用程序

Vue JS tauri 开发一个简单的PC端桌面应用程序 文章目录 Vue JS tauri 开发一个简单的PC端桌面应用程序1. 环境准备1.1 安装 Microsoft Visual Studio C 生成工具[^2]1.2 安装 Rust[^3] 2. 使用 vite 打包工具创建一个 vue 应用2.1 使用Vite创建前端Vue项目2.2 更改Vite打包…

vue中使用高德地图渲染多个不同类型的点,根据勾选数据 类型不同打点显示隐藏

一、在index.html文件中引入高德地图JavaScript API的2.0版本SDK <script src"https://webapi.amap.com/maps?v2.0&key你的高德地图Key"></script>二、创建一个Vue组件&#xff0c;用于渲染地图和点位 html <template><div class"m…

Axure全面指南:正确打开并高效使用的步骤!

AxureRP是目前流行的设计精美的用户界面和交互软件。AxureRP根据其应用领域提供了一组丰富的UI控制。作为Axure的国内替代品&#xff0c;即时设计可以在线协作&#xff0c;浏览器可以在无需下载客户端的情况下打开和使用。如果以前使用Axure&#xff0c;很容易切换到即时设计。…

记录el-select+el-tree复选框,支持模糊查询,懒加载,树父子节点不关联,不全选

需求&#xff1a;一个机构下拉菜单&#xff0c;一个人员下拉菜单&#xff0c;默认带入当前登录用户的机构和人员。机构下拉菜单为两个接口&#xff0c;模糊查询为一个接口不包含懒加载&#xff0c;默认非模糊查询情况下为一个接口&#xff0c;点击节点懒加载。机构下拉菜单数据…

探索FTP:原理、实践与安全优化

引言 在正式开始讲解之前&#xff0c;首先来了解一下文件存储的类型有哪些。 DAS、SAN和NAS是三种不同的存储架构&#xff0c;分别用于解决不同场景下的数据存储需求。 DAS (Direct Attached Storage 直接附加存储)&#xff1a;DAS 是指将存储设备&#xff08;如硬盘&#x…