Excel文件导入导出,SpringBoot整合EasyExcel批量导入导出,采用的JDBC+EasyExcel(附带整个Demo)
目录
0.为什么mybatis的foreach比JDBC的addBatch慢
1.引入依赖
2.Controller层
3.Service层
4.Utils工具类
5.自定义监听器
6.实体类
7Mapper层
不用Mybatis的原因就是因为在大量数据插入的时候jdbc性能比mybatis好
1. 首先分批读取Excel中的数据 这一点EasyExcel有自己的解决方案 2.其次就是DB里插入,怎么去插入这20w条数据 当然不能一条一条循环,应该批量插入20w条数据 3.使用JDBC+事务的批量操作将数据插入到数据库
整个Demo连接,打开下载即可,包含数据库表
整个Demo连接,打开下载即可,包含数据库表
整个Demo连接,打开下载即可,包含数据库表整个Demo连接,打开下载即可,包含数据库表
整个Demo连接,打开下载即可,包含数据库表
0.为什么mybatis的foreach比JDBC的addBatch慢
-
ORM 框架开销:MyBatis 的 foreach 操作涉及到将对象数据转换为 SQL 语句的过程,在这个过程中需要进行对象到 SQL 的映射、动态 SQL 的解析等操作,这些额外的操作会增加开销。
-
数据库连接管理:MyBatis 在执行 foreach 操作时,会频繁地获取和释放数据库连接,而数据库连接的获取和释放是一个相对耗时的操作,特别在百万级数据的情况下,这种开销可能会积累导致性能下降。
-
SQL 语句生成:MyBatis 的 foreach 操作在执行过程中会生成大量的 SQL 语句,这可能会导致数据库的缓存失效、重新编译查询计划等,从而影响性能。
-
批量插入优化:JDBC 的 addBatch 可以直接利用底层数据库的批量插入功能,而 MyBatis 的 foreach 操作在某些数据库上可能不能充分利用数据库的批量插入优化。
1.引入依赖
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version> </dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.2</version> </dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.42</version> </dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version> </dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.18</version> </dependency> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version> </dependency> <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope> </dependency>
2.Controller层
@Slf4j
@RestController
@RequestMapping("excel")
public class ExcelController {@Autowiredprivate UserService userService;//导出@GetMapping("/exportExcel")public String exportExcel(HttpServletRequest request, HttpServletResponse response){String file="D:";long startTime = System.currentTimeMillis();log.debug("-------------开始插入-------------------");userService.exportInspectionPlan(request,response);return "ok";}//导入@PostMapping("/importExcel")public void importExcel(MultipartFile multipartFile) throws IOException {if (multipartFile.isEmpty()) {return;}// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭// 这里每次会读取3000条数据 然后返回过来 直接调用使用数据就行EasyExcel.read(multipartFile.getInputStream(), ExportPlanInformationVo.class,new PageReadListener<ExportPlanInformationVo>(dataList -> {for (ExportPlanInformationVo user : dataList) {//将导入的数据用mybatisPlus一个个添加进数据库System.out.println(user);}})).sheet("现场巡视计划报表").doRead();}/*** 1. 首先分批读取Excel中的数据* 这一点EasyExcel有自己的解决方案** 2.其次就是DB里插入,怎么去插入这20w条数据* 当然不能一条一条循环,应该批量插入20w条数据* 同样不能选择Mybatis的批量插入,因为效率低** 3.使用JDBC+事务的批量操作将数据插入到数据库* *///批量导入@PostMapping("/batchImportExcel")public void batchImportExcel(MultipartFile file) throws IOException {if (BeanUtil.isEmpty(file)){log.debug("传入的文件不能为空!");return ;}if (!Objects.requireNonNull(file.getOriginalFilename()).endsWith("xls") && !file.getOriginalFilename().endsWith("xlsx")){log.debug("请上传Excel文件!");return ;}CommonExportListenerDto commonExportListenerDto = new CommonExportListenerDto();EasyExcel.read(file.getInputStream(),commonExportListenerDto).doReadAll();}
}
3.Service层
@Service
@Slf4j
public class UserService {
//@Resourceprivate IndMapper indMapper;//文件导出public void exportInspectionPlan(HttpServletRequest request, HttpServletResponse response) {//以上需要根据自己的业务去做数据处理 这里就不做展示try {//给文件命名String fileName = "ExcelTest";// 设置响应头response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("UTF-8");// 设置防止中文名乱码fileName = URLEncoder.encode(fileName, "utf-8");// 文件下载方式(附件下载还是在当前浏览器打开)response.setHeader("Content-disposition", "attachment;filename=" +fileName + ".xlsx");//向excel表格写入数据EasyExcel.write(response.getOutputStream(), ExportPlanInformationVo.class).sheet("下方导航").doWrite(getAll());
/*//下载到指定路径String fileUrl = "D://ExcelTest.xlsx";//向excel表格写入数据EasyExcel.write(fileUrl, ExportPlanInformationVo.class).sheet("下方导航").doWrite(getAll());
*/} catch (Exception e) {log.error("出现错误 {}", e);}}public List<ExportPlanInformationVo> getAll(){//根据业务逻辑获取数据
// List<ExportPlanInformationVo> all = indMapper.getAll();return indMapper.getAll();}}
4.Utils工具类
import java.sql.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;public class JDBCUtil {private static String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false";private static String username = "root";private static String password = "196713";private static String driverName = "com.mysql.jdbc.Driver";/*** 获取连接对象** @return 连接对象*/public static Connection getConnection() {Connection conn = null;try {// 1. 注册驱动Class.forName(driverName);// 2. 获取连接对象conn = DriverManager.getConnection(url, username, password);} catch (SQLException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return conn;}/*** 释放资源** @param connection 连接对象* @param statement 预编译执行对象* @param resultSet 结果集*/public static void releaseResources(Connection connection, PreparedStatement statement, ResultSet resultSet) {// 释放资源if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}}public static void insertBatch(List<Map<Object, Object>> dataList, String sql) {Connection conn = null;PreparedStatement pstm = null;try {conn = getConnection();//如果需要开启事务此处需要将自动提交关闭// conn.setAutoCommit(false);//预编译sqlpstm = (PreparedStatement) conn.prepareStatement(sql);for (Map<Object, Object> map : dataList) {//此处类型判断不完整后续可以借鉴jdk自行封装拦截器for (int i = 1; i <= map.size(); i++) {Object o = map.get(i-1);if (BeanUtil.isEmpty(o)) {pstm.setString(i, null);continue;}if (o instanceof String) {pstm.setString(i, o.toString());continue;}if (o instanceof Integer) {pstm.setInt(i, Integer.parseInt(o.toString()));continue;}if (o instanceof LocalDateTime) {pstm.setDate(i, new Date(System.currentTimeMillis()));continue;}if (o instanceof Boolean) {pstm.setBoolean(i, Boolean.parseBoolean(o.toString()));}}//添加到同一个批处理中pstm.addBatch();}//执行批处理pstm.executeBatch();//如果需要开启事务此处需要手动提交事务//conn.commit();} catch (Exception e) {e.printStackTrace();}}}
5.自定义监听器
@Data
@Slf4j
public class CommonExportListenerDto extends AnalysisEventListener<Map<Object, Object>> {/*** 表头数据(存储所有的表头数据)*/private List<Map<Integer, String>> headList = new ArrayList<>();/** 数据体*/private List<Map<Object, Object>> dataList = new ArrayList<>();/*** 存储全部表头数据* @param headMap* @param context*/@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {headList.add(headMap);}/*** 每一条数据解析都会来调用* @param data* @param context*/@Overridepublic void invoke(Map<Object, Object> data, AnalysisContext context) {dataList.add(data);if (dataList.size() >= 3) {saveData();// 存储完成清理 listdataList = ListUtils.newArrayListWithExpectedSize(2000);}}/*** 所有数据解析完成之后的操作* @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {saveData();}private void saveData() {log.info("{}条数据,开始存储数据库!", dataList.size());//批量导入JDBCUtil.insertBatch(dataList,"INSERT INTO ind (a,b,c,d,e) VALUES(?,?,?,?,?);");log.info("存储数据库成功!");}
}
6.实体类
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@HeadRowHeight(value = 30) // 头部行高
@ContentRowHeight(value = 25) // 内容行高
@ColumnWidth(value = 20) // 列宽
@HeadFontStyle(fontName = "宋体", fontHeightInPoints = 11)
public class ExportPlanInformationVo implements Serializable {// 1. 如果不想某个字段在excel中出现 可以加 @ExcelIgnore注解@ExcelProperty(value = "a")private String a;// @Dict(code = "inspectionType", fieldName = "inspectionTypeName")@ExcelProperty(value = "b")private String b;@ExcelProperty(value = "c")private String c;@ExcelProperty(value = "d")private String d;@ExcelProperty(value = "c")private String e;}
7Mapper层
@Mapper
public interface IndMapper {@Select("select * from ind")List<ExportPlanInformationVo> getAll();}
相关文章:
Excel文件导入导出,SpringBoot整合EasyExcel批量导入导出,采用的JDBC+EasyExcel(附带整个Demo)
目录 0.为什么mybatis的foreach比JDBC的addBatch慢 1.引入依赖 2.Controller层 3.Service层 4.Utils工具类 5.自定义监听器 6.实体类 7Mapper层 不用Mybatis的原因就是因为在大量数据插入的时候jdbc性能比mybatis好1. 首先分批读取Excel中的数据 这一点EasyExcel有自己…...
Git——本地使用详解
目录 Git1、开始版本控制1.1、初始化Repository1.2、使目录脱离Git控制 2、把文件交给Git管控2.1、创建文件后交给Git2.2、git add之后再次修改文件2.3、git add "--all"与"."参数区别2.4、把暂存区的内容提交到存储库里存档 3、工作区、暂存区与存储库3.1…...
深度学习pytorch——Tensor维度变换(持续更新)
view()打平函数 需要注意的是打平之后的tensor是需要有物理意义的,根据需要进行打平,并且打平后总体的大小是不发生改变的。 并且一定要谨记打平会导致维度的丢失,造成数据污染,如果想要恢复到原来的数据形式,是需要…...
Selenium-webdriver_manager判断是否已经下载过驱动(复用缓存驱动)
1,谷歌浏览器默认位置 2,ChromeDriverManager 下载的驱动位置 其中admin为机器的用户名 def installDriver(self):"""判断是否需要下载driver""""""找到本机谷歌浏览器版本""""""C:\P…...
【SQL】1174. 即时食物配送 II (窗口函数row_number; group by写法;对比;定位错因)
前述 推荐学习: 通俗易懂的学会:SQL窗口函数 题目描述 leetcode题目:1174. 即时食物配送 II 写法一:窗口函数 分组排序(以customer_id 分组,按照order_date 排序),窗口函数应用。…...
mvcc介绍
前提:在介绍mvcc之前,先简单介绍一下mysql事务的相关问题,mvcc归根结底是用来解决事务并发问题的,当然这个解决不是全部解决,只是解决了其中的一部分问题! mysql事务 一、事务的基本要素(ACID&a…...
强化PaaS平台应用安全:关键策略与措施
PaaS(平台即服务,Platform-as-a-Service)是一种云计算服务模式,可以为客户提供一个完整的云平台(硬件、软件和基础架构)以用于快捷开发、运行和管理项目,从而降低了企业云计算应用的高成本和复杂…...
K8s 集群高可用master节点ETCD挂掉如何恢复?
写在前面 很常见的集群运维场景,整理分享博文内容为 K8s 集群高可用 master 节点故障如何恢复的过程理解不足小伙伴帮忙指正 不必太纠结于当下,也不必太忧虑未来,当你经历过一些事情的时候,眼前的风景已经和从前不一样了。——村上…...
【Godot 4.2】常见几何图形、网格、刻度线点求取函数及原理总结
概述 本篇为ShapePoints静态函数库的补充和辅助文档。ShapePoints函数库是一个用于生成常见几何图形顶点数据(PackedVector2Array)的静态函数库。生成的数据可用于_draw和Line2D、Polygon2D等进行绘制和显示。因为不断地持续扩展,ShapePoint…...
如何利用POI导出报表
一、报表格式 二、依赖坐标 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.16</version> </dependency> <dependency><groupId>org.apache.poi</groupId><art…...
自动部署SSL证书到阿里云腾讯云CDN
项目地址:https://github.com/yxzlwz/ssl_update 项目简介 目前,自动申请和管理免费SSL证书的项目有很多,如个人正在使用的 acme.sh。然而在申请后,如果我们的需求不仅限于服务器本地的使用,证书的部署也是一件麻烦事…...
【系统性】 循序渐进学C++
循序渐进学C 第一阶段:基础 一、环境配置 1.1.第一个程序(基本格式) #include <iosteam> using namespace std;int main(){cout<<"hello world"<<endl;system("pause"); } 模板 #include &…...
rust - 一个日志缓存记录的通用实现
本文给出了一个通用的设计模式,通过建造者模式实例化记录对象,可自定义格式化器将实例化后的记录对象写入到指定的缓存对象中。 定义记录对象 use chrono::prelude::*; use std::{cell::RefCell, ffi::OsStr, fmt, io, io::Write, path::Path, rc::Rc,…...
elasticsearch(RestHighLevelClient API操作)(黑马)
操作全是换汤不换药,创建一个request,然后使用client发送就可以了 一、增加索引库数据 Testvoid testAddDocument() throws IOException {//从数据库查出数据Writer writer writerService.getById(199);//将查出来的数据处理成json字符串String json …...
用尾插的思想实现移除链表中的元素
目录 一、介绍尾插 1.链表为空 2.链表不为空 二、题目介绍 三、思路 四、代码 五、代码解析 1. 2. 3. 4. 5. 6. 六、注意点 1. 2. 一、介绍尾插 整体思路为 1.链表为空 void SLPushBack(SLTNode** pphead, SLTDataType x) {SLTNode* newnode BuyLTNode(x); …...
【Kubernetes】k8s删除master节点后重新加入集群
目录 前言一、思路二、实战1.安装etcdctl指令2.重置旧节点的k8s3.旧节点的的 etcd 从 etcd 集群删除4.在 master03 上,创建存放证书目录5.把其他控制节点的证书拷贝到 master01 上6.把 master03 加入到集群7.验证 master03 是否加入到 k8s 集群,检查业务…...
HCIP—OSPF虚链路实验
OSPF虚链路—Vlink 作用:专门解决OSPF不规则区域所诞生的技术,是一种虚拟的,逻辑的链路。实现非骨干区域和骨干区域在逻辑上直接连接。注意虚链路条件:只能穿越一个区域,通常对虚链路进行认证功能的配置。虚链路认证也…...
RAxML-NG安装与使用-raxml-ng-v1.2.0(bioinfomatics tools-013)
01 背景 1.1 ML树 ML树,或最大似然树,是一种在进化生物学中用来推断物种之间进化关系的方法。最大似然(Maximum Likelihood, ML)是一种统计框架,用于估计模型参数,使得观察到的数据在该模型参数下的概率最…...
Tomcat内存马
Tomcat内存马 前言 描述Servlet3.0后允许动态注册组件 这一技术的实现有赖于官方对Servlet3.0的升级,Servlet在3.0版本之后能够支持动态注册组件。 而Tomcat直到7.x才支持Servlet3.0,因此通过动态添加恶意组件注入内存马的方式适合Tomcat7.x及以上。…...
pytorch之诗词生成3--utils
先上代码: import numpy as np import settingsdef generate_random_poetry(tokenizer, model, s):"""随机生成一首诗:param tokenizer: 分词器:param model: 用于生成古诗的模型:param s: 用于生成古诗的起始字符串,默认为空串:return: …...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
