news 2026/10/25 1:01:17

ESP32-S3一键烧录包实战:完整镜像、esptool与数据边界

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ESP32-S3一键烧录包实战:完整镜像、esptool与数据边界

我手头这块ESP32-S31开发板已经折腾了两周,但真正让我下定决心做Windows一键烧录包的,不是自己烧录麻烦,而是要把固件交给别人烧。

硬件项目做久了你就知道,团队里不可能人人都会配ESP-IDF环境,生产那边的小批量烧录、现场演示时的临时更新、甚至是第二天早上你自己脑子不清醒时双击一下就想完事的那种场景,每次都敲esptool命令行是撑不住的。我见过太多人在终端里输错一个版本号、选错一个COM口,然后对着满屏的报错发呆。所以我把烧录这件事彻底“傻瓜化”:一个文件夹、一个bat、一次双击,把完整镜像、esptool环境、串口识别、日志输出全部打包进去。这篇文章就把我做这个包的过程拆开讲清楚,重点是三个绕不开的坎——完整镜像怎么生成、esptool在Windows下怎么跑得稳、以及“数据边界”这个几乎没人跟你说明白的概念。适合手里有ESP32-S31或者同类ESP32-S系列板子、想省事的开发者参考。

1. 为什么要做一键烧录包:团队协作里的“最小摩擦定律”

1.1 从一次尴尬的现场烧录说起

事情是这样的:上周客户那边要验证一个新功能,我临时改了一版固件,想请现场的A同学帮忙把板子烧一下。我把命令发过去,过了五分钟他回我一句:“我环境里面没有esptool。”再过五分钟又来一句:“装好了,但报错说找不到模块。”然后就是漫长的来回测试,那本来一分钟能搞定的事硬是折腾了半个多小时。

那次之后我就明白了一个道理:烧录固件这件事,应该像插U盘拷文件一样简单。你没法要求每个人都理解Flash布局、分区表、merge_bin这些概念,但你可以把复杂度封装起来,让别人只做“双击”这一个动作。这就是一键烧录包的价值,它不是给懂的人省时间,而是给不懂的人开一条安全通道。

1.2 一键包要解决的三类人、三类问题

我把自己以及身边同事的需求梳理了一下,发现其实就三类人:

  • 自己:每天高频烧录,不想重复敲命令,需要固定参数、日志留存、失败重试。
  • 同事:非嵌入式背景,可能是测试、硬件、生产人员,需要“双击就能烧,烧完有明确提示”。
  • 现场/产线:可能连开发环境都没有,电脑也不方便装Python,需要真正的免安装、不依赖系统的方案。

对应地,一键烧录包必须满足三个设计目标:镜像文件随包携带,绝不依赖另外去网盘下载固件;esptool环境内嵌在包内,目标机器上不需要安装任何Python或ESP-IDF;脚本参数固定,只在必要时让用户输入串口号,其他全部自动判断。

1.3 包的整体结构与制作思路

我最终做出来的目录长这样:

ESP32-S31-OneClickBurn/ ├── burn.bat # 一键烧录入口 ├── esptool/ # 便携版esptool环境 │ ├── esptool.exe # 或 esptool.py + python解释器 │ └── ... ├── firmware/ │ ├── bootloader.bin │ ├── partition-table.bin │ └── app.bin ├── combined.bin # merge后的完整镜像 ├── flash_args.txt # IDF生成的烧录参数 └── 使用说明.txt # 写给完全不懂的人看的

有人会问:既然都有esptool了,为什么不直接在命令行里烧?因为命令行给了太多自由,也就给了太多犯错的可能。一键包的核心就是把参数、完整镜像、烧录地址全部锁死,只留一个串口选择给用户。后面所有的工作,都是围绕这几个文件怎么生成、怎么驱动起来展开的。

2. 完整镜像不是“把固件拼起来”那么简单:Flash布局与merge_bin

2.1 一次烧录 vs 分次烧录:完整镜像的优势

聊到完整镜像(full image)之前,先得说清楚ESP32-S31的Flash里到底放了些什么。Flash不是一个只装固件的大仓库,它被划分为若干个区域,不同区域装不同的东西:

  • bootloader:芯片上电后最先跑的程序,负责引导和校验后续分区。
  • 分区表:告诉bootloader和App,Flash里每个区域的偏移地址、大小、用途。
  • app:你自己写的应用固件主体。
  • NVS(非易失性存储):保存Wi-Fi配置、用户参数之类的小数据。
  • OTA分区:如果有OTA升级功能,会划分出两个甚至更多app区,用于切换版本。
  • 其他数据分区:可能是蓝牙配置、文件系统、密钥等。

分次烧录的意思是,每次单独烧一个文件,比如先烧bootloader,再烧分区表,最后烧app。这样做需要操作者非常清楚每个文件应该写到哪个偏移地址,少一个、错一个,板子就可能起不来。而完整镜像是在PC端先把所有内容按照目标地址排列好,合并成一个文件,然后从Flash起始地址(0x0)一次性写入,一次烧完,地址错乱的风险被降到最低。

这就是完整镜像的核心价值:烧录动作与底层布局解耦,操作者不需要理解任何地址。

2.2 merge_bin 命令的用法与参数

生成完整镜像最常用的方法是esptool的merge_bin子命令。ESP-IDF构建完成后,会在build目录下生成一个flash_args文件,里面有所有需要烧录的文件和对应偏移地址,我的项目里它长这样:

--flash_mode keep --flash_size keep 0x1000 bootloader.bin 0x8000 partition-table.bin 0x10000 app.bin

你可以手动写这条merge_bin命令:

esptool.py merge_bin \ -o combined.bin \ --flash_mode keep \ --flash_size keep \ 0x1000 bootloader.bin \ 0x8000 partition-table.bin \ 0x10000 app.bin

生成后可以用下面的命令验证一下镜像信息:

esptool.py image_info combined.bin

它会告诉你镜像里包含了哪些段、每个段的起始地址和长度,精确到字节。我在这个阶段吃过一次哑巴亏:一开始我偷懒直接copy /b把三个bin文件首尾拼接,结果板子无限重启。原因很简单——直接拼接不保留每个文件应有的地址偏移,而bootloader找分区表是按固定地址去找的。文件内容虽然一个字节不少,但放的位置不对,整个引导链就断了。所以merge_bin这件事不能省,它不是“合并”,而是“按地址组装”。

2.3 数据边界到底在哪:地址到底是怎么排出来的

“数据边界”这个词,第一次接触的人很容易觉得抽象,但其实它就是你烧录时给的每一个偏移地址。ESP32-S31的Flash里存在着一组默认的地址约定,做完整镜像之前你必须先知道它们:

内容起始地址说明
bootloader0x1000紧跟Flash头部保留区之后
分区表0x8000bootloader之后固定预留位置
出厂app区(factory)0x10000出厂版本APP通常从这里开始
NVS根据分区表数据分区,保存用户参数
OTA app区根据分区表升级时写入的目标区域

这些地址不是拍脑袋定的,而是由芯片的启动流程和Flash扇区大小决定的。比如0x1000,是因为Flash头部有512字节的安全/校准区域,再往前留了4KB的保留区;分区表放在0x8000,是因为bootloader编译后一般不超过0x7000字节,预留到0x8000足够;app从0x10000开始,是考虑到分区表最大占用且满足4KB对齐的约定。

这里最需要注意的边界规则是:app区不能跨过它所属分区的末尾地址。如果你的app编译出来有1.5MB,而分区表给factory分配的只有1MB,镜像合并不一定报错,但烧进去之后系统会跑飞、校验失败、或者OTA时直接拒绝升级。所以我做完整镜像之前一定会做一步验证:查看构建日志里app的实际长度,再和分区表里的分区大小比对一次。

2.4 分区表布局与“合并镜像必须覆盖全Flash”吗

这里有个很多人误解的地方:完整镜像不一定要覆盖整颗Flash。很多教程会说“完整镜像要从0x0开始烧”,但这并不等于镜像文件本身要填满Flash的所有空间。

merge_bin的那几个入口(bootloader、分区表、app)合并完之后,文件末尾就是最后一个文件的结束位置。如果后面还有NVS或OTA区,它们并不会出现在镜像里,烧录后Flash的这部分仍会是空的或旧数据。所以完整镜像烧完之后,第一次开机时NVS可能是初始化的空白状态,这也解释了为什么很多板子在烧完完整镜像之后需要重新配网——因为NVS被冲掉了或者本来就没数据。

那是否需要用别的工具生成一个覆盖全Flash、连空区域都填0xFF的文件?我在量产方案里偶尔会这么做,目的是保证每颗Flash都处于完全一致的初始状态。但日常调试完全没必要。对ESP32-S31来说,最稳妥的做法是:完整镜像负责保证能开机,之后的NVS、密钥等专有数据,用单独的镜像段按需烧录或第一次启动时自动生成。不要把一切杂糅进一个文件里,否则后期维护边界会变得非常模糊。

3. esptool 在 Windows 下的环境准备:从驱动到命令行

3.1 安装方式对比与我的选择

esptool本身是一个Python工具包,但对多数Windows使用者来说,Python环境本身就是一道门槛。官方现在也提供免Python的独立可执行文件,这就省事多了。我把三种常见方式做个对比:

方式优点缺点适用场景
pip install esptool更新方便,和IDF环境互通需要目标机装Python;版本冲突风险开发者自己
官方独立可执行文件免Python,双击即用不能直接在Python脚本里import;体积稍大制作免安装包
ESP-IDF自带环境版本与IDF匹配,最稳环境庞大,其他机器难复现天天用IDF的开发机

我做一键包时用的是第二种,直接下载官方Release里的可执行版本,解压后复制到包内的esptool文件夹。原因很现实:生产那边的Windows电脑没有Python,我也不打算让他们为了烧录去装一个。但这里有个细节:独立可执行文件对Windows的PowerShell脚本限制、执行策略有要求,而.bat反而不挑这些,双击就能跑,所以我最终用bat作为外壳。

3.2 串口驱动的坑:设备管理器里永远找不到的COM口

比esptool本身更让人抓狂的是串口驱动。ESP32-S31的开发板一般通过USB转串口芯片连接电脑,常见的如CP2102、CP2105、CH340、CH9102等。板子插上之后,如果Windows没有任何反应,90%的情况是驱动没装或装错了。

我的排查顺序一直是这样的:

  1. 打开设备管理器,看“端口(COM和LPT)”下面有没有带COM号的设备。
  2. 如果看到一个带黄色感叹号的设备,说明驱动有问题,右键更新驱动。
  3. 如果完全看不到,换个USB口试试,尤其是不要插在USB Hub上。
  4. 还不行就换线。USB线看着一样,有些便宜的线只供电不传数据,这个问题我踩过不止一次。

驱动装好之后,还要注意COM口漂移的问题。同一块板子插在同一个电脑的同一个USB口,理论上COM号可能稳定,但一旦换口、换电脑、或者Windows更新了驱动,COM号可能从COM3变成COM8,烧录脚本如果写死COM口,这次能烧、下次就报错。所以我的一键脚本里做了一个小交互:自动列出所有可用COM口,让用户输入数字选择,而不是写死。

3.3 便携版环境验证

把esptool可执行文件放进包内之后,先手动验证一下能不能跑:

cd /d %~dp0 esptool\esptool.exe version esptool\esptool.exe chip_id -p COM3

version确认工具本身没问题,chip_id确认能正确连上板子并读到芯片信息。这一步能过,后面脚本的可靠性就有保障了。如果chip_id能读到序号,说明串口、驱动、esptool三者的链路全部通了,剩下的事情就是组合烧录命令。

4. 一键烧录脚本的设计:双击bat到底做了什么

4.1 脚本的完整框架

我的burn.bat核心不算复杂,但为了保证“靠谱”,每一步都做了检查和提示。完整脚本大概长这样:

@echo off setlocal enabledelayedexpansion chcp 65001 >nul cd /d %~dp0 set FIRMWARE=combined.bin set LOG=burn_log_%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%.txt rem 处理时间戳里的空格 set LOG=%LOG: =0% if not exist "%FIRMWARE%" ( echo [错误] 找不到镜像文件: %FIRMWARE% pause exit /b 1 ) echo ======================================== echo ESP32-S31 一键烧录工具 echo ======================================== echo 当前检测到的串口: powershell -NoProfile -Command "Get-CimInstance Win32_SerialPort | Select-Object -ExpandProperty DeviceID" echo. set /p PORT=请输入要使用的串口(例如COM3): if "%PORT%"=="" set PORT=COM3 echo 开始烧录,请勿断开USB连接... esptool\esptool.exe --chip esp32s3 -p %PORT% -b 460800 write_flash \ --flash_mode keep --flash_freq keep --flash_size keep \ 0x0 "%FIRMWARE%" > "%LOG%" 2>&1 if errorlevel 1 ( echo [烧录失败] 请查看日志后重试:%LOG% pause exit /b 1 ) echo [烧录成功] pause

我在脚本里做了几件事:强制用脚本所在目录作为工作目录,免得用户在别的路径下双击导致找不到文件;镜像文件存在性检查,少了就直接退出并提示,避免走到烧录那一步才报错;输出重定向到日志文件,烧录失败时不是干瞪眼看屏幕一条条滚动,而是能留下记录;errorlevel检查退出码。esptool成功返回0,任何失败都会返回非0值,这个判断一定不能省。

4.2 为什么用esptool.exe而不是esptool.py

这里也许有人会问:网上大部分教程都用esptool.py,我为什么偏偏挑esptool.exe?原因有三:Windows上.py文件的默认关联程序不一定存在,如果目标电脑装了多个Python版本,双击bat调起python esptool.py可能会命中一个缺少依赖的虚拟环境;esptool.exe把Python运行时一并打包了,体积大一点但换来的是环境可控;独立的exe在退出码的传递上更干净,不容易被奇怪的Python包装器吞掉返回状态。一键烧录包就是要“环境不可控时也能跑”,所以独立exe是更合适的选择。

4.3 脚本双击闪退的排查思路

做完脚本第一个版本,我在另一台干净Windows机器上测试,双击bat后窗口一闪就没了,连错误都看不见。后来排查发现是启动时chcp 65001那段语句在部分系统上因为代码页切换权限问题直接抛错退出。还有一次是因为我把bat放在了中文路径下,脚本里的cd /d %~dp0和esptool路径组合不当,导致路径解析失败。排查这类“闪退”问题,最有效的办法是别双击,而是打开cmd窗口后直接把bat文件拖进去回车,这样就算脚本中途出错,窗口也不会关闭,你能看到是哪一行报错。另外在关键步骤之间加pause也能快速锁定问题范围。所以最终版本我不管成功失败,都留了一个pause在最后,至少让使用者知道发生了什么事。

4.4 串口自动检测的权衡

我用PowerShell列举串口,有读者可能觉得不够“自动化”,为什么不直接全自动识别板子?我也试过自动遍历COM1到COM256,逐个发chip_id指令探测,找到就烧。听起来很美,但实测下来有两个问题:

  • 遍历过程很慢,每个不存在的COM口要等超时,用户体验并不好。
  • 有些USB转串口设备会在探测时被唤醒,反复探测可能导致状态异常。

所以我最终放弃了全自动探测,只显示当前可用串口列表、让人选一下。对使用者来说,多花五秒钟输入COM号,换来的是极高的稳定性,非常值得。

5. 数据边界的进阶问题:擦除范围、OTA与Flash加密

5.1 为什么不建议随便用 erase_flash

很多人烧板子遇到异常,第一反应就是erase_flash全部擦除重来。这个操作在大方向上没错,但“全部擦除”这件事本身就有数据边界问题。

ESP32-S31的Flash里除了app之外,还可能保存着NVS数据、Wi-Fi校准数据、蓝牙绑定信息、用于Flash加密的密钥,甚至量产配置。erase_flash会把所有这些一并抹掉。如果这块板子是刚从工厂出来的,擦掉倒没什么;但如果它已经被客户使用过,里面有设备证书或用户参数,这一擦就可能造成麻烦。

我在调试日常固件时,其实只需要烧app.bin,让bootloader和分区表保持不变。这样NVS区域会原样保留,测试设备不用每次都重新配网、重新绑定。所以我的经验是:平时烧录用“分区烧录”,把变更限制在app区;只有做完整镜像验证、或者怀疑分区表被改坏时,才动用完整镜像+全擦。把烧录范围当作数据边界来管理,能帮你省掉大量无意义的重复配置。

5.2 write_flash 只覆盖你指定的地址,其他区域是旧的

esptool的write_flash按偏移地址写入,它不会先擦除整颗Flash。假如你之前烧过一版1MB大小的app,后来app编译出来不到300KB,重新烧录后,app区末尾到原1MB边界之间会残留旧固件的“尸体”。大多数情况下这些残留无害,但在某些需要做Flash加密或签名校验的场景,未覆盖区域可能会被当作有效代码段来校验,导致启动异常。

因此,判断是否需要全擦,有一个简单原则:如果镜像内容和上次烧录的布局在逻辑上不连续,或者你改了Flash大小/加密设置,先全擦;如果只是改了几行代码、分区布局没动,直接覆盖烧app即可。这比“每次烧之前都擦一遍”安全得多,也快得多。

5.3 OTA升级包的边界:它不是完整镜像

有人会拿“完整OTA镜像链接”里的文件过来问:这个固件包能不能直接当完整镜像烧?这就是把“OTA镜像”和“完整烧录镜像”混为一谈了。OTA升级包一般只包含一个app段,它为了节省流量和内存,去掉了bootloader和分区表,甚至在app头部做了差分压缩。但完整烧录镜像必须包含引导链路的三件套,缺了任何一个,上电都进不了系统。

这一点在数据边界上的体现尤其明显:OTA升级包本身是不带“从哪里开始写”的地图信息的,它依赖设备已经存在的分区表去决定下载后写入哪里;而完整烧录镜像则主动把每个组件都钉死在固定地址上。两者的设计目标完全不同,烧录时的信任边界也不同。我见过有人图省事,用OTA镜像直接merge到完整镜像里,结果偏移地址错乱,板子直接变砖。所以做镜像时一定要确认来源:IDF构建生成并已在flash_args里列出地址的是烧录镜像,从设备里抓出来的是备份,网络上单独下载的app文件是OTA包,三者不要混用。

5.4 从启动日志里读出真实边界

验证数据边界最靠谱的方法,不是猜,而是直接看芯片启动时打印的信息。ESP32-S31上电后bootloader会在串口输出分区表概览,包含每个分区的类型、偏移地址、大小、标志位。我烧完板子第一件事就是打开串口监视器,看那一段日志,确认实际生效的地址和我烧录镜像时填的地址一致。确认行的关键字一般是nvs、phy_init、factory、ota_0之类的分区名,后面跟着十六进制偏移和十进制大小。

这里有个细节值得提醒:分区表里factory分区和ota_0、ota_1分区的偏移,直接决定app能不能顺利运行。如果app是支持OTA的,而你在完整镜像里没有包含OTA分区的内容,那你烧进去的镜像本质上是“残缺”的——它能开机,但一旦触发升级,OTA请求会写入一个空区域,升级校验必失败。所以如果你做的是一个带OTA能力的完整镜像,建议把ota_0、ota_1分区至少也纳入镜像的规划,哪怕初始内容是空的,也要让分区表的布局和实际Flash状态一致。

6. 实测中的意外情况与最终建议

6.1 串口被占用时的正确处理

这是我在做一键烧录包过程中踩过最多坑的地方。烧录进行到一半提示Failed to open serial port,多半不是驱动坏了,而是另一个程序占用了串口。最常见的是串口监视器没关——你刚才看日志用的那个窗口,只要没随手关掉,COM口就会被一直锁住。esptool在Windows下对这种冲突毫不留情,直接报错退出。

处理办法很直接:关掉所有占用串口的程序再试。如果实在找不到是谁占用的,打开设备管理器找到对应COM口,右键属性看“位置路径”,或者用任务管理器结束可疑的监视器进程。有几次我还遇到过“板子看起来没占用,但就是连不上”的情况,重启Windows也不肯好,最后发现是USB总线上的残留状态没清干净,拔掉USB线等十秒再插,问题就解决了。

6.2 关于权限一个反直觉的点:别用管理员权限跑烧录脚本

我的第一版脚本用了管理员权限,因为我觉得访问硬件串口可能需要提权。实测后我发现恰恰相反:esptool访问串口完全不需要管理员权限,而且管理员会话在某些Windows版本上有可能会干扰USB串口桥接设备的底层枚举逻辑,导致状态异常。有一次我在管理员终端里跑脚本,esptool反复报告timed out,换成普通用户权限之后反而一次通过。后来我干脆在脚本里加了一个静默判断,发现当前会话有管理员权限就在日志里提醒一句“当前以管理员身份运行,如遇异常请尝试普通权限”,但没有强制阻止。

6.3 波特率不是越高越好

我最初把烧录波特率设成921600,想着速度快一点。实测中,921600在一部分板子上稳定跑完,但在另一批板子上经常报A fatal error occurred: Packet content transfer stopped。后来我统一改成460800,故障率基本归零。对调试来说,460800已经很快了,单片2MB镜像十几秒就完事,没必要为了那几秒去赌运气。如果你的USB线比较长或者用了USB Hub,建议从230400起步,稳定优先。

6.4 一键烧录包的最终目录和建议

完成所有测试之后,我并没有把事情停在“能做出来”的层面。为了让别人用起来更不容易犯错,我做了两个小优化:把镜像文件名带上了版本号和日期,比如combined_v1.2.3_20250618.bin,这样即使以后包多了也不会糊里糊涂烧错;在脚本末尾烧录成功时顺手用了系统提示音加文本提示,让站在操作者身后的人也能知道烧完了。

如果你也想做这么一套包,我建议按顺序来:先在命令行里手动确认chip_id能读到,再做merge_bin生成完整镜像并用image_info验证地址,然后写脚本,脚本先在本机测通,最后拿到一台完全没装任何Python环境的Windows电脑上做最终验收。整个流程并不复杂,最花时间的往往是驱动和路径问题。我做这套包花了大概一个下午,之后的收益,是每次烧录都只需要双击一下。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/25 1:01:00

FSoE黑通道原理与实战:功能安全通信的核心设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/25 1:00:59

从TMN到q3接口:传输网管的功能结构与信息模型解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/25 1:00:27

[GraphRAG实现原理-01]让LLM基于构建的知识图谱回答问题

GraphRAG是一种结构化的、分层的检索增强生成 (RAG) 方法,它不同于使用纯文本片段的简单语义搜索方法。GraphRAG的流程包括:从原始文本中提取知识图谱,构建社群层级结构,为这些社群生成摘要,然后在执行基于 RAG 的任务…

作者头像 李华
网站建设 2026/10/25 0:30:00

H3CNE-MSA存储认证:DAS/NAS/SAN与RAID快照考点

简介:面向备考 H3C 认证工程师-MSA 存储(H3CNE-MSA)的考生与技术人员的题库文档,聚焦 H3C 代理 MSA 存储设备的基础配置与维护知识,适合希望系统梳理知识点、检验掌握程度并冲刺认证的初、中级存储工程师。压缩包内仅 …

作者头像 李华
网站建设 2026/10/25 0:19:51

OpenMetadata Docker安装排错:环境、下载、编排、访问四层拆解

简介:《openMetadata docker 安装》是一份面向运维人员、数据平台开发者及系统管理员的实操文档,围绕在 CentOS 7 上使用 Docker 与 Docker Compose 部署 OpenMetadata 元数据管理平台展开,适合需要快速搭建数据发现、数据血缘、数据质量与数…

作者头像 李华
网站建设 2026/10/24 23:50:37

MyBatisPlus批量插入性能优化与实现方案

1. 为什么需要自己实现MyBatisPlus批量插入MyBatisPlus作为MyBatis的增强工具,虽然提供了基础的CRUD操作,但在批量插入场景下存在几个明显的痛点。首先是性能问题,默认的saveBatch()方法实际上是通过for循环执行单条INSERT语句,当…

作者头像 李华