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

EasyExcel快速导出 100W 数据

一. 简介

导出是后台管理系统的常用功能,当数据量特别大的时候会内存溢出和卡顿页面,曾经自己封装过一个导出,采用了分批查询数据来避免内存溢出和使用SXSSFWorkbook方式缓存数据到文件上以解决下载大文件EXCEL卡死页面的问题。

不过一是存在封装不太友好使用不方便的问题,二是这些poi的操作方式仍然存在内存占用过大的问题,三是存在空循环和整除的时候数据有缺陷的问题,以及存在内存溢出的隐患。

无意间查询到阿里开源的EasyExcel框架,发现可以将解析的EXCEL的内存占用控制在KB级别,并且绝对不会内存溢出(内部实现待研究),还有就是速度极快,大概100W条记录,十几个字段,只需要70秒即可完成下载。

遂抛弃自己封装的,转战研究阿里开源的EasyExcel. 不过 说实话,当时自己封装的那个还是有些技术含量的,例如:外观模式,模板方法模式,以及委托思想,组合思想,可以看看。另外,微信搜索关注Java技术栈,发送:设计模式,可以获取我整理的 Java 设计模式实战教程。

EasyExcel的github地址是:https://github.com/alibaba/easyexcel

二. 案例

2.1 POM依赖

<!-- 阿里开源EXCEL -->
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>1.1.1</version>
</dependency>

2.2 POJO对象

package com.authorization.privilege.excel;import java.util.Date;/*** @author qjwyss* @description*/
public class User {private String uid;private String name;private Integer age;private Date birthday;public User() {}public User(String uid, String name, Integer age, Date birthday) {this.uid = uid;this.name = name;this.age = age;this.birthday = birthday;}public String getUid() {return uid;}public void setUid(String uid) {this.uid = uid;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}
}

2.3 测试环境

2.3.1.数据量少的(20W以内吧):一个SHEET一次查询导出

如果数据量过大,不要用传统分页,利用where id> #{lastMaxId} order by id limit 100,解决分页慢的问题

/*** 针对较少的记录数(20W以内大概)可以调用该方法一次性查出然后写入到EXCEL的一个SHEET中* 注意: 一次性查询出来的记录数量不宜过大,不会内存溢出即可。** @throws IOException*/
@Test
public void writeExcelOneSheetOnceWrite() throws IOException {// 生成EXCEL并指定输出路径OutputStream out = new FileOutputStream("E:\\temp\\withoutHead1.xlsx");ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);// 设置SHEETSheet sheet = new Sheet(1, 0);sheet.setSheetName("sheet1");// 设置标题Table table = new Table(1);List<List<String>> titles = new ArrayList<List<String>>();titles.add(Arrays.asList("用户ID"));titles.add(Arrays.asList("名称"));titles.add(Arrays.asList("年龄"));titles.add(Arrays.asList("生日"));table.setHead(titles);// 查询数据导出即可 比如说一次性总共查询出100条数据List<List<String>> userList = new ArrayList<>();for (int i = 0; i < 100; i++) {userList.add(Arrays.asList("ID_" + i, "小明" + i, String.valueOf(i), new Date().toString()));}writer.write0(userList, sheet, table);writer.finish();
}

2.3.2.数据量适中(100W以内):一个SHEET分批查询导出

/*** 针对105W以内的记录数可以调用该方法分多批次查出然后写入到EXCEL的一个SHEET中* 注意:* 每次查询出来的记录数量不宜过大,根据内存大小设置合理的每次查询记录数,不会内存溢出即可。* 数据量不能超过一个SHEET存储的最大数据量105W** @throws IOException*/
@Test
public void writeExcelOneSheetMoreWrite() throws IOException {// 生成EXCEL并指定输出路径OutputStream out = new FileOutputStream("E:\\temp\\withoutHead2.xlsx");ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);// 设置SHEETSheet sheet = new Sheet(1, 0);sheet.setSheetName("sheet1");// 设置标题Table table = new Table(1);List<List<String>> titles = new ArrayList<List<String>>();titles.add(Arrays.asList("用户ID"));titles.add(Arrays.asList("名称"));titles.add(Arrays.asList("年龄"));titles.add(Arrays.asList("生日"));table.setHead(titles);// 模拟分批查询:总记录数50条,每次查询20条,  分三次查询 最后一次查询记录数是10Integer totalRowCount = 50;Integer pageSize = 20;Integer writeCount = totalRowCount % pageSize == 0 ? (totalRowCount / pageSize) : (totalRowCount / pageSize + 1);// 注: 此处仅仅为了模拟数据,实用环境不需要将最后一次分开,合成一个即可, 参数为:currentPage = i+1;  pageSize = pageSizefor (int i = 0; i < writeCount; i++) {// 前两次查询 每次查20条数据if (i < writeCount - 1) {List<List<String>> userList = new ArrayList<>();for (int j = 0; j < pageSize; j++) {userList.add(Arrays.asList("ID_" + Math.random(), "小明", String.valueOf(Math.random()), new Date().toString()));}writer.write0(userList, sheet, table);} else if (i == writeCount - 1) {// 最后一次查询 查多余的10条记录List<List<String>> userList = new ArrayList<>();Integer lastWriteRowCount = totalRowCount - (writeCount - 1) * pageSize;for (int j = 0; j < lastWriteRowCount; j++) {userList.add(Arrays.asList("ID_" + Math.random(), "小明", String.valueOf(Math.random()), new Date().toString()));}writer.write0(userList, sheet, table);}}writer.finish();
}

2.3.3.数据量很大(几百万都行):多个SHEET分批查询导出

/*** 针对几百万的记录数可以调用该方法分多批次查出然后写入到EXCEL的多个SHEET中* 注意:* perSheetRowCount % pageSize要能整除  为了简洁,非整除这块不做处理* 每次查询出来的记录数量不宜过大,根据内存大小设置合理的每次查询记录数,不会内存溢出即可。** @throws IOException*/
@Test
public void writeExcelMoreSheetMoreWrite() throws IOException {// 生成EXCEL并指定输出路径OutputStream out = new FileOutputStream("E:\\temp\\withoutHead3.xlsx");ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);// 设置SHEET名称String sheetName = "测试SHEET";// 设置标题Table table = new Table(1);List<List<String>> titles = new ArrayList<List<String>>();titles.add(Arrays.asList("用户ID"));titles.add(Arrays.asList("名称"));titles.add(Arrays.asList("年龄"));titles.add(Arrays.asList("生日"));table.setHead(titles);// 模拟分批查询:总记录数250条,每个SHEET存100条,每次查询20条  则生成3个SHEET,前俩个SHEET查询次数为5, 最后一个SHEET查询次数为3 最后一次写的记录数是10// 注:该版本为了较少数据判断的复杂度,暂时perSheetRowCount要能够整除pageSize, 不去做过多处理  合理分配查询数据量大小不会内存溢出即可。Integer totalRowCount = 250;Integer perSheetRowCount = 100;Integer pageSize = 20;Integer sheetCount = totalRowCount % perSheetRowCount == 0 ? (totalRowCount / perSheetRowCount) : (totalRowCount / perSheetRowCount + 1);Integer previousSheetWriteCount = perSheetRowCount / pageSize;Integer lastSheetWriteCount = totalRowCount % perSheetRowCount == 0 ?previousSheetWriteCount :(totalRowCount % perSheetRowCount % pageSize == 0 ? totalRowCount % perSheetRowCount / pageSize : (totalRowCount % perSheetRowCount / pageSize + 1));for (int i = 0; i < sheetCount; i++) {// 创建SHEETSheet sheet = new Sheet(i, 0);sheet.setSheetName(sheetName + i);if (i < sheetCount - 1) {// 前2个SHEET, 每个SHEET查5次 每次查20条 每个SHEET写满100行  2个SHEET合计200行  实用环境:参数:currentPage: j+1 + previousSheetWriteCount*i, pageSize: pageSizefor (int j = 0; j < previousSheetWriteCount; j++) {List<List<String>> userList = new ArrayList<>();for (int k = 0; k < 20; k++) {userList.add(Arrays.asList("ID_" + Math.random(), "小明", String.valueOf(Math.random()), new Date().toString()));}writer.write0(userList, sheet, table);}} else if (i == sheetCount - 1) {// 最后一个SHEET 实用环境不需要将最后一次分开,合成一个即可, 参数为:currentPage = i+1;  pageSize = pageSizefor (int j = 0; j < lastSheetWriteCount; j++) {// 前俩次查询 每次查询20条if (j < lastSheetWriteCount - 1) {List<List<String>> userList = new ArrayList<>();for (int k = 0; k < 20; k++) {userList.add(Arrays.asList("ID_" + Math.random(), "小明", String.valueOf(Math.random()), new Date().toString()));}writer.write0(userList, sheet, table);} else if (j == lastSheetWriteCount - 1) {// 最后一次查询 将剩余的10条查询出来List<List<String>> userList = new ArrayList<>();Integer lastWriteRowCount = totalRowCount - (sheetCount - 1) * perSheetRowCount - (lastSheetWriteCount - 1) * pageSize;for (int k = 0; k < lastWriteRowCount; k++) {userList.add(Arrays.asList("ID_" + Math.random(), "小明1", String.valueOf(Math.random()), new Date().toString()));}writer.write0(userList, sheet, table);}}}}writer.finish();
}

2.4 生产环境

2.4.0.Excel常量类

package com.authorization.privilege.constant;/*** @author qjwyss* @description EXCEL常量类*/
public class ExcelConstant {/*** 每个sheet存储的记录数 100W*/public static final Integer PER_SHEET_ROW_COUNT = 1000000;/*** 每次向EXCEL写入的记录数(查询每页数据大小) 20W*/public static final Integer PER_WRITE_ROW_COUNT = 200000;}
注:为了书写方便,此处俩个必须要整除,可以省去很多不必要的判断。另外如果自己测试,可以改为100,20。
分享给你: Spring Boot 学习笔记。

2.4.1.数据量少的(20W以内吧):一个SHEET一次查询导出

@Override
public ResultVO<Void> exportSysSystemExcel(SysSystemVO sysSystemVO, HttpServletResponse response) throws Exception {ServletOutputStream out = null;try {out = response.getOutputStream();ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);// 设置EXCEL名称String fileName = new String(("SystemExcel").getBytes(), "UTF-8");// 设置SHEET名称Sheet sheet = new Sheet(1, 0);sheet.setSheetName("系统列表sheet1");// 设置标题Table table = new Table(1);List<List<String>> titles = new ArrayList<List<String>>();titles.add(Arrays.asList("系统名称"));titles.add(Arrays.asList("系统标识"));titles.add(Arrays.asList("描述"));titles.add(Arrays.asList("状态"));titles.add(Arrays.asList("创建人"));titles.add(Arrays.asList("创建时间"));table.setHead(titles);// 查数据写EXCELList<List<String>> dataList = new ArrayList<>();List<SysSystemVO> sysSystemVOList = this.sysSystemReadMapper.selectSysSystemVOList(sysSystemVO);if (!CollectionUtils.isEmpty(sysSystemVOList)) {sysSystemVOList.forEach(eachSysSystemVO -> {dataList.add(Arrays.asList(eachSysSystemVO.getSystemName(),eachSysSystemVO.getSystemKey(),eachSysSystemVO.getDescription(),eachSysSystemVO.getState().toString(),eachSysSystemVO.getCreateUid(),eachSysSystemVO.getCreateTime().toString()));});}writer.write0(dataList, sheet, table);// 下载EXCELresponse.setHeader("Content-Disposition", "attachment;filename=" + new String((fileName).getBytes("gb2312"), "ISO-8859-1") + ".xls");response.setContentType("multipart/form-data");response.setCharacterEncoding("utf-8");writer.finish();out.flush();} finally {if (out != null) {try {out.close();} catch (Exception e) {e.printStackTrace();}}}return ResultVO.getSuccess("导出系统列表EXCEL成功");
}

2.4.2.数据量适中(100W以内):一个SHEET分批查询导出

@Override
public ResultVO<Void> exportSysSystemExcel(SysSystemVO sysSystemVO, HttpServletResponse response) throws Exception {ServletOutputStream out = null;try {out = response.getOutputStream();ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);// 设置EXCEL名称String fileName = new String(("SystemExcel").getBytes(), "UTF-8");// 设置SHEET名称Sheet sheet = new Sheet(1, 0);sheet.setSheetName("系统列表sheet1");// 设置标题Table table = new Table(1);List<List<String>> titles = new ArrayList<List<String>>();titles.add(Arrays.asList("系统名称"));titles.add(Arrays.asList("系统标识"));titles.add(Arrays.asList("描述"));titles.add(Arrays.asList("状态"));titles.add(Arrays.asList("创建人"));titles.add(Arrays.asList("创建时间"));table.setHead(titles);// 查询总数并 【封装相关变量 这块直接拷贝就行 不要改动】Integer totalRowCount = this.sysSystemReadMapper.selectCountSysSystemVOList(sysSystemVO);Integer pageSize = ExcelConstant.PER_WRITE_ROW_COUNT;Integer writeCount = totalRowCount % pageSize == 0 ? (totalRowCount / pageSize) : (totalRowCount / pageSize + 1);// 写数据 这个i的最大值直接拷贝就行了 不要改for (int i = 0; i < writeCount; i++) {List<List<String>> dataList = new ArrayList<>();// 此处查询并封装数据即可 currentPage, pageSize这个变量封装好的 不要改动PageHelper.startPage(i + 1, pageSize);List<SysSystemVO> sysSystemVOList = this.sysSystemReadMapper.selectSysSystemVOList(sysSystemVO);if (!CollectionUtils.isEmpty(sysSystemVOList)) {sysSystemVOList.forEach(eachSysSystemVO -> {dataList.add(Arrays.asList(eachSysSystemVO.getSystemName(),eachSysSystemVO.getSystemKey(),eachSysSystemVO.getDescription(),eachSysSystemVO.getState().toString(),eachSysSystemVO.getCreateUid(),eachSysSystemVO.getCreateTime().toString()));});}writer.write0(dataList, sheet, table);}// 下载EXCELresponse.setHeader("Content-Disposition", "attachment;filename=" + new String((fileName).getBytes("gb2312"), "ISO-8859-1") + ".xls");response.setContentType("multipart/form-data");response.setCharacterEncoding("utf-8");writer.finish();out.flush();} finally {if (out != null) {try {out.close();} catch (Exception e) {e.printStackTrace();}}}return ResultVO.getSuccess("导出系统列表EXCEL成功");
}

2.4.3.数据里很大(几百万都行):多个SHEET分批查询导出

@Override
public ResultVO<Void> exportSysSystemExcel(SysSystemVO sysSystemVO, HttpServletResponse response) throws Exception {ServletOutputStream out = null;try {out = response.getOutputStream();ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);// 设置EXCEL名称String fileName = new String(("SystemExcel").getBytes(), "UTF-8");// 设置SHEET名称String sheetName = "系统列表sheet";// 设置标题Table table = new Table(1);List<List<String>> titles = new ArrayList<List<String>>();titles.add(Arrays.asList("系统名称"));titles.add(Arrays.asList("系统标识"));titles.add(Arrays.asList("描述"));titles.add(Arrays.asList("状态"));titles.add(Arrays.asList("创建人"));titles.add(Arrays.asList("创建时间"));table.setHead(titles);// 查询总数并封装相关变量(这块直接拷贝就行了不要改)Integer totalRowCount = this.sysSystemReadMapper.selectCountSysSystemVOList(sysSystemVO);Integer perSheetRowCount = ExcelConstant.PER_SHEET_ROW_COUNT;Integer pageSize = ExcelConstant.PER_WRITE_ROW_COUNT;Integer sheetCount = totalRowCount % perSheetRowCount == 0 ? (totalRowCount / perSheetRowCount) : (totalRowCount / perSheetRowCount + 1);Integer previousSheetWriteCount = perSheetRowCount / pageSize;Integer lastSheetWriteCount = totalRowCount % perSheetRowCount == 0 ?previousSheetWriteCount :(totalRowCount % perSheetRowCount % pageSize == 0 ? totalRowCount % perSheetRowCount / pageSize : (totalRowCount % perSheetRowCount / pageSize + 1));for (int i = 0; i < sheetCount; i++) {// 创建SHEETSheet sheet = new Sheet(i, 0);sheet.setSheetName(sheetName + i);// 写数据 这个j的最大值判断直接拷贝就行了,不要改动for (int j = 0; j < (i != sheetCount - 1 ? previousSheetWriteCount : lastSheetWriteCount); j++) {List<List<String>> dataList = new ArrayList<>();// 此处查询并封装数据即可 currentPage, pageSize这俩个变量封装好的 不要改动PageHelper.startPage(j + 1 + previousSheetWriteCount * i, pageSize);List<SysSystemVO> sysSystemVOList = this.sysSystemReadMapper.selectSysSystemVOList(sysSystemVO);if (!CollectionUtils.isEmpty(sysSystemVOList)) {sysSystemVOList.forEach(eachSysSystemVO -> {dataList.add(Arrays.asList(eachSysSystemVO.getSystemName(),eachSysSystemVO.getSystemKey(),eachSysSystemVO.getDescription(),eachSysSystemVO.getState().toString(),eachSysSystemVO.getCreateUid(),eachSysSystemVO.getCreateTime().toString()));});}writer.write0(dataList, sheet, table);}}// 下载EXCELresponse.setHeader("Content-Disposition", "attachment;filename=" + new String((fileName).getBytes("gb2312"), "ISO-8859-1") + ".xls");response.setContentType("multipart/form-data");response.setCharacterEncoding("utf-8");writer.finish();out.flush();} finally {if (out != null) {try {out.close();} catch (Exception e) {e.printStackTrace();}}}return ResultVO.getSuccess("导出系统列表EXCEL成功");
}

三、总结

造的假数据,100W条记录,18个字段,测试导出是70s。在实际上产环境使用的时候,具体的还是要看自己写的sql的性能。sql性能快的话,会很快。

有一点推荐一下:在做分页的时候使用单表查询, 对于所需要处理的外键对应的冗余字段,在外面一次性查出来放到map里面(推荐使用@MapKey注解),然后遍历list的时候根据外键从map中获取对应的名称。

一个宗旨:少发查询sql, 才能更快的导出。

题外话:如果数据量过大,不要用传统分页,利用where id> #{lastMaxId} order by id limit 100,解决分页慢的问题

相关文章:

EasyExcel快速导出 100W 数据

一. 简介 导出是后台管理系统的常用功能&#xff0c;当数据量特别大的时候会内存溢出和卡顿页面&#xff0c;曾经自己封装过一个导出&#xff0c;采用了分批查询数据来避免内存溢出和使用SXSSFWorkbook方式缓存数据到文件上以解决下载大文件EXCEL卡死页面的问题。 不过一是存…...

SpingBoot的项目实战--模拟电商【5.沙箱支付】

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于SpringBoot电商项目的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一. 沙箱支付是什么 二.Sp…...

How to collect data

How to collect data 爬虫JavaPythonurllibrequestsBeautifulSoup 反爬虫信息校验型反爬虫动态渲染反爬虫文本混淆反爬虫特征识别反爬虫App反爬虫验证码 自动化测试工具SeleniumAppiumQMetry Automation StudioTestComplete RPA商业化产品艺赛旗影刀UIPath 开源产品Robot Frame…...

二刷Laravel 教程(用户注册)总结Ⅳ

一、显示用户信息 1&#xff09;resource Route::resource(users, UsersController); 相当于下面这7个路由 我们先用 Artisan 命令查看目前应用的路由&#xff1a; php artisan route:list 2&#xff09; compact 方法 //我们将用户对象 $user 通过 compact 方法转化为一个关联…...

跨国制造业组网方案解析,如何实现总部-分支稳定互联?

既要控制成本&#xff0c;又要稳定高效&#xff0c;可能吗&#xff1f; 在制造企业积极向“智造”发展、数字化转型的当下&#xff0c;物联网、人工智能、机器人等新型设备加入到生产、管理环节&#xff0c;为企业内部数据传输提出了更高的要求。而当企业规模扩大&#xff0c;数…...

网络的设置

一、网络设置 1.1查看linux基础的网络设置 网关 route -n ip地址ifconfigDNS服务器cat /etc/resolv.conf主机名hostname路由 route -n 网络连接状态ss 或者 netstat域名解析nslookup host 例题&#xff1a;除了ping&#xff0c;什么命令可以测试DNS服务器来解…...

CentOS常用命令

CentOS常用命令 1 背景知识1.1 Centos 简介1.2 centos 和ubuntu的区别1.3 安装centos的时候需要注意什么 2 常用命令集锦2.1 文件目录类&#xff1a;2.2 驱动挂载类&#xff1a;2.3 关机命令&#xff1a;2.4 查看系统信息命令&#xff1a;2.5 文本命令2.6 系统管理命令&#xf…...

Linux运维之切换到 root 用户

春花秋月何时了,往事知多少。此付费专栏不要订阅,不要订阅,听人劝。 🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 系列专栏目录 [Java项目实战] 介绍Java…...

【2024系统架构设计】 系统架构设计师第二版-层次式架构设计理论与实践

目录 一 表现层框架设计 二 中间层架构设计 三 数据访问层设计 四 数据架构规划与设计 五 物联网层次架构设计 六 层次式架构案例分析...

SpringSecurity的注解@PreAuthorize的失效问题

问题&#xff1a;测试响应式框架时&#xff0c;测试框架对于权限与角色的拦截问题&#xff0c;对于/delete的访问报错访问拒绝&#xff0c;但是数据里面配置了权限。 配置详情 原因&#xff1a;调用roles方法时源码会重新new一个list将authorities的数据覆盖&#xff0c;导致…...

k8s的集群调度

1、scheduler&#xff1a;负责调度资源&#xff0c;把pod调度到指定的node节点 &#xff08;1&#xff09;预算策略 &#xff08;2&#xff09;优先策略 2、List-watch &#xff08;1&#xff09;在k8s集群中&#xff0c;通过List-watch的机制进行每个组件的协作&#xff0…...

简单易懂的理解 PyTorch 中 Transformer 组件

目录 torch.nn子模块transformer详解 nn.Transformer Transformer 类描述 Transformer 类的功能和作用 Transformer 类的参数 forward 方法 参数 输出 示例代码 注意事项 nn.TransformerEncoder TransformerEncoder 类描述 TransformerEncoder 类的功能和作用 Tr…...

搭建Eureka服务注册中心

一、前言 我们在别的章节中已经详细讲解过eureka注册中心的作用&#xff0c;本节会简单讲解eureka作用&#xff0c;侧重注册中心的搭建。 Eureka作为服务注册中心可以进行服务注册和服务发现&#xff0c;注册在上面的服务可以到Eureka上进行服务实例的拉取&#xff0c;主要作用…...

【React】react-router-dom中的HashRouter和BrowserRouter实现原理

1. 前言 在之前整理BOM的五个对象时&#xff0c;提到&#xff1a; location.hash发生改变后&#xff0c;会触发hashchange事件&#xff0c;且history栈中会增加一条记录&#xff0c;但页面不会重新加载——实现HashRouter的关键history.pushState(state, , URL)执行后&#xf…...

生物信息学中的可重复性研究

科学就其本质而言&#xff0c;是累积渐进的。无论你是使用基于网络的还是基于命令行的工具&#xff0c;在进行研究时都应保证该研究可被其他研究人员重复。这有利于你的工作的累积与进展。在生物信息学领域&#xff0c;这意味着如下内容。 工作流应该有据可查。这可能包括在电脑…...

css-img图像同比缩小

1. HTML 中使图像按比例缩小 CSS 来控制图像的大小&#xff0c;并保持其宽高比 <!DOCTYPE html> <html> <head><style>.image-container {width: 300px; /* 设置容器宽度 */height: auto; /* 让高度自适应 */}.image-container img {width: 100%; /* …...

SpringBoot+Prometheus+Grafana搭建应用监控系统

1.应用监控系统介绍 SpringBoot的应用监控方案比较多&#xff0c;SpringBootPrometheusGrafana是比较常用的一种解决方案&#xff0c;主要的监控数据的处理逻辑如下&#xff1a; SpringBoot 的 actuator 提供了应用监控端点&#xff0c;可以对外暴露监控数据信息。Prometheu…...

QT c++和qml交互实例

文章目录 一、demo效果图二、c和qml交互的基本方式1、qml 调用 C 类对象2、C 类对象调用 qml3、qml 给 C 发送信号4、C 给 qml 发送信号 三、关键代码1、工程结构图2、c代码MainWindow.cppMainQuickView.cppStudentInfoView.cppStudentInfoModel.cpp 3、qml代码main.qmlMainQui…...

mysql基础-数据操作之增删改

目录 1.新增数据 1.1单条数据新增 1.2多条数据新增 1.3查询数据新增 2.更新 2.1单值更新 2.2多值更新 2.3批量更新 2.3.1 批量-单条件更新 2.3.2批量-多条件更新 2.4 插入或更新 2.5 联表更新 3.删除 本次分享一下数据库的DML操作语言。 操作表的数据结构&#xf…...

写字母(文件)

请编写函数&#xff0c;将大写字母写入文件中。 函数原型 void WriteLetter(FILE *f, int n);说明&#xff1a;参数 f 为文件指针&#xff0c;n 为字母数目(1 ≤ n ≤ 26)。函数将前 n 个大写英文字母写入 f 所指示的文件中。 裁判程序 #include <stdio.h> #include &…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

【堆垛策略】设计方法

堆垛策略的设计是积木堆叠系统的核心&#xff0c;直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法&#xff0c;涵盖基础规则、优化算法和容错机制&#xff1a; 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则&#xff1a; 大尺寸/重量积木在下&#xf…...