[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"site-config":3,"primary-menu":6,"cat-mybatis-plus":85,"catposts-mybatis-plus":97,"post-detail-post-mybatisplus-batch-insert-0dfcd5a6":484},{"config":4,"socialLinks":5},null,[],{"metadata":7,"spec":10,"menuItems":20},{"name":8,"creationTimestamp":9},"primary","2026-09-12T06:13:55.024154Z",{"displayName":11,"menuItems":12},"主菜单",[13,14,15,16,17,18,19],"88c3f10b-321c-4092-86a8-70db00251b74","menu-item-izrtmxer","c4c814d1-0c2c-456b-8c96-4864965fee94","menu-item-column","menu-item-tools","menu-item-zsxq","menu-item-ocrxlczu",[21,30,40,49,58,67,76],{"displayName":22,"metadata":23,"spec":25,"status":28,"children":29},"首页",{"name":13,"creationTimestamp":24},"2026-09-12T06:13:54.422830Z",{"displayName":22,"href":26,"priority":27,"menuName":8},"\u002F",0,{"displayName":22,"href":26},[],{"displayName":31,"metadata":32,"spec":34,"status":38,"children":39},"Java面试八股",{"name":14,"creationTimestamp":33},"2026-09-13T09:42:02.854891Z",{"displayName":31,"href":35,"target":36,"priority":37,"menuName":8},"\u002Fjava-interview","_self",1,{"displayName":31,"href":35},[],{"displayName":41,"metadata":42,"spec":44,"status":47,"children":48},"文章",{"name":15,"creationTimestamp":43},"2026-09-12T06:13:54.457307Z",{"displayName":41,"href":45,"priority":46,"menuName":8},"\u002Farchives",2,{"displayName":41,"href":45},[],{"displayName":50,"metadata":51,"spec":53,"status":56,"children":57},"项目实战",{"name":16,"creationTimestamp":52},"2026-09-14T00:35:08.138170Z",{"displayName":50,"href":54,"target":36,"priority":55,"menuName":8},"\u002Fcolumn",3,{"displayName":50,"href":54},[],{"displayName":59,"metadata":60,"spec":62,"status":65,"children":66},"在线工具",{"name":17,"creationTimestamp":61},"2026-09-14T00:35:08.171474Z",{"displayName":59,"href":63,"target":36,"priority":64,"menuName":8},"\u002Ftools",4,{"displayName":59,"href":63},[],{"displayName":68,"metadata":69,"spec":71,"status":74,"children":75},"知识星球",{"name":18,"creationTimestamp":70},"2026-09-14T00:35:08.199145Z",{"displayName":68,"href":72,"target":36,"priority":73,"menuName":8},"\u002Fzsxq",5,{"displayName":68,"href":72},[],{"displayName":77,"metadata":78,"spec":80,"status":83,"children":84},"特价云服务器",{"name":19,"creationTimestamp":79},"2026-09-25T15:30:59.201614Z",{"displayName":77,"href":81,"target":36,"priority":82,"menuName":8},"\u002Fserver",6,{"displayName":77,"href":81},[],{"metadata":86,"spec":89,"status":94,"postCount":96},{"name":87,"creationTimestamp":88},"mybatis-plus","2026-09-12T08:22:53.466780Z",{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},"MyBatis Plus 教程","\u002Fupload\u002Ftutorial-cover-mybatis-plus.png","MyBatis-Plus 从入门到实战：条件构造器、通用 CRUD、分页插件、代码生成与多租户。",false,{"permalink":95,"postCount":96,"visiblePostCount":96},"\u002Fcategories\u002Fmybatis-plus",18,[98,122,144,166,187,208,230,251,273,294,315,336,356,377,398,419,441,463],{"metadata":99,"spec":102,"status":113,"categories":117},{"name":100,"creationTimestamp":101},"post-mybatisplus-wrapper-condition-0f52be04","2026-09-12T08:30:08.659081Z",{"title":103,"slug":104,"cover":105,"excerpt":106,"publishTime":108,"categories":109,"tags":110,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus Condition 详解（结合代码示例）","mybatisplus-wrapper-condition","\u002Fupload\u002F167344247547271-zSIv.jpg",{"raw":107,"autoGenerate":93},"前面小节中，我们已经学习了 Mybatis Plus 中使用频率超高的条件构造器，应该有会注意到很多方法中，都有一个 boolean 类型的 condition 字段，如下面的截图，这玩意到底是干嘛用的呢...","2026-09-12T08:30:08.716991Z",[87],[],"PUBLIC",true,{"permalink":114,"excerpt":107,"lastModifyTime":115,"phase":116},"\u002Farchives\u002Fmybatisplus-wrapper-condition","2026-09-13T05:25:08.061777Z","PUBLISHED",[118],{"metadata":119,"spec":120,"status":121,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":123,"spec":126,"status":135,"categories":139},{"name":124,"creationTimestamp":125},"post-mybatisplus-quick-start-7438e7a7","2026-09-12T08:30:08.027221Z",{"title":127,"slug":128,"cover":129,"excerpt":130,"publishTime":132,"categories":133,"tags":134,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 快速开始","mybatisplus-quick-start","\u002Fupload\u002F164870371940555-tWiM.png",{"raw":131,"autoGenerate":93},"大家好，前面小节中，我们已经了解到什么是 Mybatis Plus， 以及和 Mybatis 的区别。本章节中，我们将上手学习如何使用它操作数据库...","2026-09-12T08:30:08.104840Z",[87],[],{"permalink":136,"excerpt":137,"lastModifyTime":138,"phase":116},"\u002Farchives\u002Fmybatisplus-quick-start","前面小节中，我们已经了解到什么是 Mybatis Plus， 以及和 Mybatis 的区别。本章节中，我们将上手学习如何使用它操作数据库...","2026-09-13T05:25:08.633120Z",[140],{"metadata":141,"spec":142,"status":143,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":145,"spec":148,"status":157,"categories":161},{"name":146,"creationTimestamp":147},"post-mybatisplus-print-sql-6fd9382a","2026-09-12T08:30:07.357056Z",{"title":149,"slug":150,"cover":151,"excerpt":152,"publishTime":154,"categories":155,"tags":156,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 打印 SQL 语句（包含执行耗时）","mybatisplus-print-sql","\u002Fupload\u002F167091605638716-eGlp.jpg",{"raw":153,"autoGenerate":93},"大家好，项目中使用 Mybatis Plus 框架操作数据库时，如果是在本地开发（生产环境不推荐打印执行 SQL，会有数据泄漏风险），很希望完整的打印一下执行的 SQL，以及执行耗时，一方面可以方便调试，另一方面通过执行耗时，可以提醒我们改进一些慢 SQL...","2026-09-12T08:30:07.418896Z",[87],[],{"permalink":158,"excerpt":159,"lastModifyTime":160,"phase":116},"\u002Farchives\u002Fmybatisplus-print-sql","项目中使用 Mybatis Plus 框架操作数据库时，如果是在本地开发（生产环境不推荐打印执行 SQL，会有数据泄漏风险），很希望完整的打印一下执行的 SQL，以及执行耗时，一方面可以方便调试，另一方面通过执行耗时，可以提醒我们改进一些慢 SQL...","2026-09-13T05:25:11.894390Z",[162],{"metadata":163,"spec":164,"status":165,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":167,"spec":170,"status":179,"categories":182},{"name":168,"creationTimestamp":169},"post-mybatisplus-page-query-cf6b396c","2026-09-12T08:30:06.634372Z",{"title":171,"slug":172,"cover":173,"excerpt":174,"publishTime":176,"categories":177,"tags":178,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 分页查询数据（图解）","mybatisplus-page-query","\u002Fupload\u002F167246380737773-bixm.jpg",{"raw":175,"autoGenerate":93},"本小节中，我们将学习如何通过 Mybatis Plus 分页查询数据库表中的数据。下图是我从京东上查询关键词「手机」 ，展示的手机数据就是分页查询，共有 91 页...","2026-09-12T08:30:06.704298Z",[87],[],{"permalink":180,"excerpt":175,"lastModifyTime":181,"phase":116},"\u002Farchives\u002Fmybatisplus-page-query","2026-09-13T05:25:14.891109Z",[183],{"metadata":184,"spec":185,"status":186,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":188,"spec":191,"status":200,"categories":203},{"name":189,"creationTimestamp":190},"post-mybatisplus-optimistic-lock-ad7ba0dc","2026-09-12T08:30:05.848176Z",{"title":192,"slug":193,"cover":194,"excerpt":195,"publishTime":197,"categories":198,"tags":199,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 乐观锁插件（手把手教学）","mybatisplus-optimistic-lock","\u002Fupload\u002F167333816060936-YNck.jpg",{"raw":196,"autoGenerate":93},"程序设计中，若遇到高并发场景，需要多线程修改共享资源的时候，为了保证数据的原子性，就需要频繁使用到锁。锁的类型也有很多，如互斥锁、自旋锁、读写锁、悲观锁、乐观锁等，因为本文主要内容是 Mybatis Plus 实现乐观锁功能，就不展开讲了...","2026-09-12T08:30:05.904951Z",[87],[],{"permalink":201,"excerpt":196,"lastModifyTime":202,"phase":116},"\u002Farchives\u002Fmybatisplus-optimistic-lock","2026-09-13T05:25:15.535552Z",[204],{"metadata":205,"spec":206,"status":207,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":209,"spec":212,"status":221,"categories":225},{"name":210,"creationTimestamp":211},"post-mybatisplus-insert-508e1eef","2026-09-12T08:30:05.087286Z",{"title":213,"slug":214,"cover":215,"excerpt":216,"publishTime":218,"categories":219,"tags":220,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 新增数据并返回主键 ID（图文讲解）","mybatisplus-insert","\u002Fupload\u002F167204808139593-dWMf.jpg",{"raw":217,"autoGenerate":93},"大家好，本小节中，我们将学习如何通过 Mybatis Plus 框架给数据库表新增数据。","2026-09-12T08:30:05.152745Z",[87],[],{"permalink":222,"excerpt":223,"lastModifyTime":224,"phase":116},"\u002Farchives\u002Fmybatisplus-insert","本小节中，我们将学习如何通过 Mybatis Plus 框架给数据库表新增数据。","2026-09-13T05:25:18.910864Z",[226],{"metadata":227,"spec":228,"status":229,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":231,"spec":234,"status":243,"categories":246},{"name":232,"creationTimestamp":233},"post-mybatisplus-dynamic-table-name-2454e803","2026-09-12T08:30:04.221155Z",{"title":235,"slug":236,"cover":237,"excerpt":238,"publishTime":240,"categories":241,"tags":242,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 动态表名（图文讲解）","mybatisplus-dynamic-table-name","\u002Fupload\u002F167420281572597-bWCR.jpg",{"raw":239,"autoGenerate":93},"本小节中，我们将学习如何在 Mybatis Plus 中实现动态表名。啥是动态表名呢？我们都知道，当数据库单表存储数据太多时（比如单表超过 1000 万条数据），会严重影响查询效率，这就需要进行水平切分操作，将数据分别存储到不同表中...","2026-09-12T08:30:04.292849Z",[87],[],{"permalink":244,"excerpt":239,"lastModifyTime":245,"phase":116},"\u002Farchives\u002Fmybatisplus-dynamic-table-name","2026-09-13T05:25:20.735247Z",[247],{"metadata":248,"spec":249,"status":250,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":252,"spec":255,"status":264,"categories":268},{"name":253,"creationTimestamp":254},"post-mybatisplus-delete-2134cc6a","2026-09-12T08:30:03.191339Z",{"title":256,"slug":257,"cover":258,"excerpt":259,"publishTime":261,"categories":262,"tags":263,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 删除数据（超详细）","mybatisplus-delete","\u002Fupload\u002F167214854711359-XVkX.jpg",{"raw":260,"autoGenerate":93},"大家好，本小节中，我们将学习如何通过 Mybatis Plus 删除数据库表中的数据。为了演示删除数据，在前面小节中，我们已经定义好了一个用于测试的用户表， 执行脚本如下...","2026-09-12T08:30:03.250941Z",[87],[],{"permalink":265,"excerpt":266,"lastModifyTime":267,"phase":116},"\u002Farchives\u002Fmybatisplus-delete","本小节中，我们将学习如何通过 Mybatis Plus 删除数据库表中的数据。为了演示删除数据，在前面小节中，我们已经定义好了一个用于测试的用户表， 执行脚本如下...","2026-09-13T05:25:21.767837Z",[269],{"metadata":270,"spec":271,"status":272,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":274,"spec":277,"status":286,"categories":289},{"name":275,"creationTimestamp":276},"post-mybatisplus-batch-insert-0dfcd5a6","2026-09-12T08:30:02.464761Z",{"title":278,"slug":279,"cover":280,"excerpt":281,"publishTime":283,"categories":284,"tags":285,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 批量 Insert_新增数据（图文讲解）","mybatisplus-batch-insert","\u002Fupload\u002F167211863047181-DEdJ.jpg",{"raw":282,"autoGenerate":93},"本小节中，我们将学习如何通过 Mybatis Plus 实现 MySQL 批量插入数据。先抛出一个问题：假设老板给你下了个任务，向数据库中添加 100 万条数据，并且不能耗时太久...","2026-09-12T08:30:02.543036Z",[87],[],{"permalink":287,"excerpt":282,"lastModifyTime":288,"phase":116},"\u002Farchives\u002Fmybatisplus-batch-insert","2026-09-13T05:25:24.064210Z",[290],{"metadata":291,"spec":292,"status":293,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":295,"spec":298,"status":307,"categories":310},{"name":296,"creationTimestamp":297},"post-mybatis-plus-integrate-0c3e6619","2026-09-12T08:30:01.532093Z",{"title":299,"slug":300,"cover":301,"excerpt":302,"publishTime":304,"categories":305,"tags":306,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis-Plus 整合集成","mybatis-plus-integrate","\u002Fupload\u002F164870378749787-sJrg.png",{"raw":303,"autoGenerate":93},"上小节中，我们学习了如何快速入门 Mybatis-Plus，文中以 Spring Boot + Maven 来讲解的，本文将详细的介绍如何在市面主流框架中整合&amp;集成 Mybatis-Plus。","2026-09-12T08:30:01.743646Z",[87],[],{"permalink":308,"excerpt":303,"lastModifyTime":309,"phase":116},"\u002Farchives\u002Fmybatis-plus-integrate","2026-09-16T09:43:57.945654Z",[311],{"metadata":312,"spec":313,"status":314,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":316,"spec":319,"status":328,"categories":331},{"name":317,"creationTimestamp":318},"post-mybaitsplus-wrapper-51f1c68c","2026-09-12T08:30:00.818539Z",{"title":320,"slug":321,"cover":322,"excerpt":323,"publishTime":325,"categories":326,"tags":327,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus Wrapper 条件构造器（超详细）","mybaitsplus-wrapper","\u002Fupload\u002F167220794094570-TBuu.jpg",{"raw":324,"autoGenerate":93},"在 Mybatis 中，我们查询或者更新指定数据，可以直接在 xml 文件中写 SQL，然后通过占位符传入条件参数即可，比如你想根据用户 ID 去更新某个用户数据，那么 SQL 条件大致为 where id = #{id}...","2026-09-12T08:30:00.907062Z",[87],[],{"permalink":329,"excerpt":324,"lastModifyTime":330,"phase":116},"\u002Farchives\u002Fmybaitsplus-wrapper","2026-09-13T05:25:26.773490Z",[332],{"metadata":333,"spec":334,"status":335,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":337,"spec":340,"status":348,"categories":351},{"name":338,"creationTimestamp":339},"post-mybaitsplus-update-7910a075","2026-09-12T08:30:00.045046Z",{"title":341,"slug":342,"cover":215,"excerpt":343,"publishTime":345,"categories":346,"tags":347,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 更新数据（图文讲解）","mybaitsplus-update",{"raw":344,"autoGenerate":93},"本小节中，我们将学习如何通过 Mybatis Plus 修改数据库表中的数据。在前面小节中，我们已经定义好了一个用于测试的用户表， 执行脚本如下...","2026-09-12T08:30:00.114111Z",[87],[],{"permalink":349,"excerpt":344,"lastModifyTime":350,"phase":116},"\u002Farchives\u002Fmybaitsplus-update","2026-09-13T05:25:27.532631Z",[352],{"metadata":353,"spec":354,"status":355,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":357,"spec":360,"status":369,"categories":372},{"name":358,"creationTimestamp":359},"post-mybaitsplus-select-data-bd965549","2026-09-12T08:29:59.301200Z",{"title":361,"slug":362,"cover":363,"excerpt":364,"publishTime":366,"categories":367,"tags":368,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 查询数据（图文讲解）","mybaitsplus-select-data","\u002Fupload\u002F167238066532413-dlWV.jpg",{"raw":365,"autoGenerate":93},"本小节中，我们将学习如何通过 Mybatis Plus 查询数据库表中的数据。在前面小节中，我们已经定义好了一个用于测试的用户表， 执行脚本如下...","2026-09-12T08:29:59.380954Z",[87],[],{"permalink":370,"excerpt":365,"lastModifyTime":371,"phase":116},"\u002Farchives\u002Fmybaitsplus-select-data","2026-09-13T05:25:28.466672Z",[373],{"metadata":374,"spec":375,"status":376,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":378,"spec":381,"status":390,"categories":393},{"name":379,"creationTimestamp":380},"post-mybaitsplus-logic-delete-22e24533","2026-09-12T08:29:58.277662Z",{"title":382,"slug":383,"cover":384,"excerpt":385,"publishTime":387,"categories":388,"tags":389,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 逻辑删除（手把手教学）","mybaitsplus-logic-delete","\u002Fupload\u002F167342448565316-QpIC.jpg",{"raw":386,"autoGenerate":93},"本小节中，我们将学习如何通过 Mybatis Plus 实现逻辑删除功能。讲逻辑删除之前，先说说物理删除。当我们想要删除数据库中的数据，都会执行一条 delete 语句，执行成功后...","2026-09-12T08:29:58.346883Z",[87],[],{"permalink":391,"excerpt":386,"lastModifyTime":392,"phase":116},"\u002Farchives\u002Fmybaitsplus-logic-delete","2026-09-13T05:25:29.585172Z",[394],{"metadata":395,"spec":396,"status":397,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":399,"spec":402,"status":411,"categories":414},{"name":400,"creationTimestamp":401},"post-mybaitsplus-join-query-0b894da6","2026-09-12T08:29:57.423004Z",{"title":403,"slug":404,"cover":405,"excerpt":406,"publishTime":408,"categories":409,"tags":410,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 多表联查（包含分页关联查询,图文讲解）","mybaitsplus-join-query","\u002Fupload\u002F167273442141335-DKZI.jpg",{"raw":407,"autoGenerate":93},"本小节中，我们将学习如何通过 Mybatis Plus 实现多表关联查询，以及分页关联查询。本文以查询用户所下订单，来演示 Mybatis Plus 的关联查询，数据库表除了前面小节中已经定义好的用户表...","2026-09-12T08:29:57.518395Z",[87],[],{"permalink":412,"excerpt":407,"lastModifyTime":413,"phase":116},"\u002Farchives\u002Fmybaitsplus-join-query","2026-09-13T05:25:32.424638Z",[415],{"metadata":416,"spec":417,"status":418,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":420,"spec":423,"status":432,"categories":436},{"name":421,"creationTimestamp":422},"post-mybaitsplus-enum-value-745dbc08","2026-09-12T08:29:56.730649Z",{"title":424,"slug":425,"cover":426,"excerpt":427,"publishTime":429,"categories":430,"tags":431,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 通用枚举（图文讲解）","mybaitsplus-enum-value","\u002Fupload\u002F167359425246371-MHdo.jpg",{"raw":428,"autoGenerate":93},"\r\n大家好，本小节中，我们将讲解 Mybatis Plus 通用枚举的用法。那么，什么是通用枚举呢？之前小节中，我们的用户表有个性别字段 gender，在插入数据时，我们的示例代码大致如下...","2026-09-12T08:29:56.787230Z",[87],[],{"permalink":433,"excerpt":434,"lastModifyTime":435,"phase":116},"\u002Farchives\u002Fmybaitsplus-enum-value","本小节中，我们将讲解 Mybatis Plus 通用枚举的用法。那么，什么是通用枚举呢？之前小节中，我们的用户表有个性别字段 gender，在插入数据时，我们的示例代码大致如下...","2026-09-13T05:25:33.487169Z",[437],{"metadata":438,"spec":439,"status":440,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":442,"spec":445,"status":454,"categories":458},{"name":443,"creationTimestamp":444},"post-mybaitsplus-common-annotation-80f197dc","2026-09-12T08:29:56.056296Z",{"title":446,"slug":447,"cover":448,"excerpt":449,"publishTime":451,"categories":452,"tags":453,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 常用注解（超详细）","mybaitsplus-common-annotation","\u002Fupload\u002F167334634342163-ZyfL.jpg",{"raw":450,"autoGenerate":93},"大家好，本文主要带大家来看下 Mybatis Plus 框架中，使用频率非常高的几个注解及其属性值，因为编写此本教程目的是为了大家快速入门并使用 Mybatis Plus，关于注解更高级的用法请参考官网...","2026-09-12T08:29:56.114067Z",[87],[],{"permalink":455,"excerpt":456,"lastModifyTime":457,"phase":116},"\u002Farchives\u002Fmybaitsplus-common-annotation","本文主要带大家来看下 Mybatis Plus 框架中，使用频率非常高的几个注解及其属性值，因为编写此本教程目的是为了大家快速入门并使用 Mybatis Plus，关于注解更高级的用法请参考官网...","2026-09-13T05:25:33.983128Z",[459],{"metadata":460,"spec":461,"status":462,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":464,"spec":467,"status":476,"categories":479},{"name":465,"creationTimestamp":466},"post-mybaitsplus-code-generator-c984d27c","2026-09-12T08:29:55.452199Z",{"title":468,"slug":469,"cover":470,"excerpt":471,"publishTime":473,"categories":474,"tags":475,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},"Mybatis Plus 代码生成器（图文讲解）","mybaitsplus-code-generator","\u002Fupload\u002F167387297654896-aKtE.jpg",{"raw":472,"autoGenerate":93},"本小节中，我们将学习如何使用 Mybatis Plus 的代码生成器。可能有效小伙伴会疑惑，这玩意是干嘛使的？通常在实际项目开发中，如果开发一个功能，我们会先进行表设计，技术方案的确定，技术经理评估 OK 以后，才会进行项目开发，而不是一上来就写代码，跟无头苍蝇一样...","2026-09-12T08:29:55.508709Z",[87],[],{"permalink":477,"excerpt":472,"lastModifyTime":478,"phase":116},"\u002Farchives\u002Fmybaitsplus-code-generator","2026-09-13T05:25:35.131214Z",[480],{"metadata":481,"spec":482,"status":483,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"metadata":485,"spec":486,"status":490,"categories":491,"content":496},{"name":275,"creationTimestamp":276},{"title":278,"slug":279,"cover":280,"excerpt":487,"publishTime":283,"categories":488,"tags":489,"priority":27,"pinned":93,"deleted":93,"visible":111,"allowComment":112},{"raw":282,"autoGenerate":93},[87],[],{"permalink":287,"excerpt":282,"lastModifyTime":288,"phase":116},[492],{"metadata":493,"spec":494,"status":495,"postCount":96},{"name":87,"creationTimestamp":88},{"displayName":90,"slug":87,"cover":91,"description":92,"priority":27,"hideFromList":93,"preventParentPostCascadeQuery":93},{"permalink":95,"postCount":96,"visiblePostCount":96},{"content":497,"raw":498},"\u003Cp>\u003C\u002Fp>\n\u003Cp>本小节中，我们将学习如何通过 Mybatis Plus 实现 MySQL 批量插入数据。\u003C\u002Fp>\n\u003Ch2>什么是批量插入？优势在哪里？\u003C\u002Fh2>\n\u003Cp>\u003Cem>先抛出一个问题：假设老板给你下了个任务，向数据库中添加 100 万条数据，并且不能耗时太久！\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>通常来说，我们向 MySQL 中新增一条记录，SQL 语句类似如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>INSERT INTO `t_user` (`name`, `age`, `gender`) VALUES ('张三0', 0, 1);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>如果你需要添加 100 万条数据，就需要多次执行此语句，这就意味着频繁地 IO 操作（网络 IO、磁盘 IO），并且每一次数据库执行 SQL 都需要进行解析、优化等操作，都会导致非常耗时。\u003C\u002Fp>\n\u003Cp>幸运的是，MySQL 支持一条 SQL 语句可以批量插入多条记录，格式如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>INSERT INTO `t_user` (`name`, `age`, `gender`) VALUES ('张三0', 0, 1), ('张三1', 0, 1), ('张三3', 0, 1);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>和常规的 \u003Ccode>INSERT\u003C\u002Fcode> 语句不同的是，\u003Ccode>VALUES\u003C\u002Fcode> 支持多条记录，通过 \u003Ccode>,\u003C\u002Fcode> 逗号隔开。这样，可以实现一次性插入多条记录。\u003C\u002Fp>\n\u003Cp>数据量不多的情况下，常规 \u003Ccode>INSERT\u003C\u002Fcode> 和批量插入性能差距不大，但是，一旦数量级上去后，执行耗时差距就拉开了，在后面我们会实测一下它们之间的耗时对比。\u003C\u002Fp>\n\u003Ch2>表与实体类\u003C\u002Fh2>\n\u003Cp>先创建一个测试表 \u003Ccode>t_user\u003C\u002Fcode>, 执行脚本如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>DROP TABLE IF EXISTS user;\n\nCREATE TABLE `t_user` (\n  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',\n  `name` varchar(30) NOT NULL DEFAULT '' COMMENT '姓名',\n  `age` int(11) NULL DEFAULT NULL COMMENT '年龄',\n  `gender` tinyint(2) NOT NULL DEFAULT 0 COMMENT '性别，0：女 1：男',\n  PRIMARY KEY (`id`)\n) COMMENT = '用户表';\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>再定义一个名为 \u003Ccode>User\u003C\u002Fcode> 实体类：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\n@Data\n@TableName(&quot;t_user&quot;)\npublic class User {\n    \u002F**\n     * 主键 ID, @TableId 注解定义字段为表的主键，type 表示主键类型，IdType.AUTO 表示随着数据库 ID 自增\n     *\u002F\n    @TableId(type = IdType.AUTO)\n    private Long id;\n    \u002F**\n     * 姓名\n     *\u002F\n    private String name;\n    \u002F**\n     * 年龄\n     *\u002F\n    private Integer age;\n    \u002F**\n     * 性别\n     *\u002F\n    private Integer gender;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cblockquote>\n\u003Cp>TIP： \u003Ccode>@Data\u003C\u002Fcode> 是 Lombok 注解，偷懒用的，加上它即可免写繁杂的 \u003Ccode>getXXX\u002FsetXXX\u003C\u002Fcode> 相关方法，不了解的小伙伴可自行搜索一下如何使用。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2>Mybatis Plus 伪批量插入\u003C\u002Fh2>\n\u003Cp>在前面《新增数据》\u003Cspan>\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" style=\"color: #aaa; margin-left: 3px;\" aria-hidden=\"true\" focusable=\"false\" x=\"0px\" y=\"0px\" viewBox=\"0 0 100 100\" width=\"15\" height=\"15\" class=\"icon outbound\">\u003Cpath fill=\"currentColor\" d=\"M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z\">\u003C\u002Fpath> \u003Cpolygon fill=\"currentColor\" points=\"45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9\">\u003C\u002Fpolygon>\u003C\u002Fsvg> \u003Cspan class=\"sr-only\">\u003C\u002Fspan>\u003C\u002Fspan>小节中，我们已经知道了 Mybatis Plus 内部封装的批量插入 \u003Ccode>savaBatch()\u003C\u002Fcode> 是个\u003Cstrong>假的批量插入\u003C\u002Fstrong>，示例代码如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>List&lt;User&gt; users = new ArrayList&lt;&gt;();\nfor (int i = 0; i &lt; 5; i++) {\n    User user = new User();\n    user.setName(&quot;张三&quot; + i);\n    user.setAge(i);\n    user.setGender(1);\n    users.add(user);\n}\n\u002F\u002F 批量插入\nboolean isSuccess = userService.saveBatch(users);\nSystem.out.println(&quot;isSuccess:&quot; + isSuccess);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>通过打印实际执行 SQL , 我们发现还是一条一条的执行 \u003Ccode>INSERT\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cp>\n\u003Cimg src=\"\u002Fupload\u002F167211863047181-DEdJ.jpg\" loading=\"lazy\">\n\u003C\u002Fp>\n\u003Cp>并且还带着大家看了内部实现的源码，这种方式比起自己 \u003Ccode>for\u003C\u002Fcode> 循环一条一条 \u003Ccode>INSERT\u003C\u002Fcode> 插入数据性能要更高，原因是在\u003Cstrong>会话这块做了优化\u003C\u002Fstrong>，虽然实际执行并不是真的批量插入。\u003C\u002Fp>\n\u003Ch2>利用 SQL 注入器实现真的批量插入\u003C\u002Fh2>\n\u003Cp>接下来，本文就手把手带你通过 Mybatis Plus 框架的 SQL 注入器实现一个真的批量插入。\u003C\u002Fp>\n\u003Ch3>示例项目结构\u003C\u002Fh3>\n\u003Cp>先贴一张示例项目的结构：\u003C\u002Fp>\n\u003Cp>\n\u003Cimg src=\"\u002Fupload\u002F167291645197992-KIGA.jpg\" loading=\"lazy\">\n\u003C\u002Fp>\n\u003Cp>注意看我红线标注的部分，主要关注这 4 个类与接口。\u003C\u002Fp>\n\u003Ch3>新建批量插入 SQL 注入器\u003C\u002Fh3>\n\u003Cp>在工程 \u003Ccode>config\u003C\u002Fcode> 目录下创建一个 SQL 注入器 \u003Ccode>InsertBatchSqlInjector\u003C\u002Fcode>  ：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * @author: 张三\n * @date: 2023-01-05 14:42\n * @version: v1.0.0\n * @description: 批量插入 SQL 注入器\n **\u002F\npublic class InsertBatchSqlInjector extends DefaultSqlInjector {\n\n    @Override\n    public List&lt;AbstractMethod&gt; getMethodList(Class&lt;?&gt; mapperClass, TableInfo tableInfo) {\n    \t\u002F\u002F super.getMethodList() 保留 Mybatis Plus 自带的方法\n        List&lt;AbstractMethod&gt; methodList = super.getMethodList(mapperClass, tableInfo);\n        \u002F\u002F 添加自定义方法：批量插入，方法名为 insertBatchSomeColumn\n        methodList.add(new InsertBatchSomeColumn());\n        return methodList;\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch4>说说 InsertBatchSomeColumn\u003C\u002Fh4>\n\u003Cp>\u003Ccode>InsertBatchSomeColumn\u003C\u002Fcode> 是 Mybatis Plus 内部提供的默认批量插入，只不过这个方法作者只在 MySQL 数据测试过，所以没有将它作为通用方法供外部调用，注意看注释：\u003C\u002Fp>\n\u003Cp>\n\u003Cimg src=\"\u002Fupload\u002F167291823412173-zlfC.jpg\" loading=\"lazy\">\n\u003C\u002Fp>\n\u003Cp>源码复制出来，如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * 批量新增数据,自选字段 insert\n * &lt;p&gt; 不同的数据库支持度不一样!!!  只在 mysql 下测试过!!!  只在 mysql 下测试过!!!  只在 mysql 下测试过!!! &lt;\u002Fp&gt;\n * &lt;p&gt; 除了主键是 &lt;strong&gt; 数据库自增的未测试 &lt;\u002Fstrong&gt; 外理论上都可以使用!!! &lt;\u002Fp&gt;\n * &lt;p&gt; 如果你使用自增有报错或主键值无法回写到entity,就不要跑来问为什么了,因为我也不知道!!! &lt;\u002Fp&gt;\n * &lt;p&gt;\n * 自己的通用 mapper 如下使用:\n * &lt;pre&gt;\n * int insertBatchSomeColumn(List&lt;T&gt; entityList);\n * &lt;\u002Fpre&gt;\n * &lt;\u002Fp&gt;\n *\n * &lt;li&gt; 注意: 这是自选字段 insert !!,如果个别字段在 entity 里为 null 但是数据库中有配置默认值, insert 后数据库字段是为 null 而不是默认值 &lt;\u002Fli&gt;\n *\n * &lt;p&gt;\n * 常用的 {@link Predicate}:\n * &lt;\u002Fp&gt;\n *\n * &lt;li&gt; 例1: t -&gt; !t.isLogicDelete() , 表示不要逻辑删除字段 &lt;\u002Fli&gt;\n * &lt;li&gt; 例2: t -&gt; !t.getProperty().equals(&quot;version&quot;) , 表示不要字段名为 version 的字段 &lt;\u002Fli&gt;\n * &lt;li&gt; 例3: t -&gt; t.getFieldFill() != FieldFill.UPDATE) , 表示不要填充策略为 UPDATE 的字段 &lt;\u002Fli&gt;\n *\n * @author miemie\n * @since 2018-11-29\n *\u002F\n\n@SuppressWarnings(&quot;serial&quot;)\npublic class InsertBatchSomeColumn extends AbstractMethod {\n\n    \u002F**\n     * 字段筛选条件\n     *\u002F\n    @Setter\n    @Accessors(chain = true)\n    private Predicate&lt;TableFieldInfo&gt; predicate;\n\n    \u002F**\n     * 默认方法名\n     *\u002F\n    public InsertBatchSomeColumn() {\n    \t\u002F\u002F 方法名\n        super(&quot;insertBatchSomeColumn&quot;);\n    }\n\n    \u002F**\n     * 默认方法名\n     *\n     * @param predicate 字段筛选条件\n     *\u002F\n    public InsertBatchSomeColumn(Predicate&lt;TableFieldInfo&gt; predicate) {\n        super(&quot;insertBatchSomeColumn&quot;);\n        this.predicate = predicate;\n    }\n\n    \u002F**\n     * @param name      方法名\n     * @param predicate 字段筛选条件\n     * @since 3.5.0\n     *\u002F\n    public InsertBatchSomeColumn(String name, Predicate&lt;TableFieldInfo&gt; predicate) {\n        super(name);\n        this.predicate = predicate;\n    }\n\n    @SuppressWarnings(&quot;Duplicates&quot;)\n    @Override\n    public MappedStatement injectMappedStatement(Class&lt;?&gt; mapperClass, Class&lt;?&gt; modelClass, TableInfo tableInfo) {\n        KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;\n        SqlMethod sqlMethod = SqlMethod.INSERT_ONE;\n        List&lt;TableFieldInfo&gt; fieldList = tableInfo.getFieldList();\n        String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(true, false) +\n            this.filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY);\n        String columnScript = LEFT_BRACKET + insertSqlColumn.substring(0, insertSqlColumn.length() - 1) + RIGHT_BRACKET;\n        String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(true, ENTITY_DOT, false) +\n            this.filterTableFieldInfo(fieldList, predicate, i -&gt; i.getInsertSqlProperty(ENTITY_DOT), EMPTY);\n        insertSqlProperty = LEFT_BRACKET + insertSqlProperty.substring(0, insertSqlProperty.length() - 1) + RIGHT_BRACKET;\n        String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, &quot;list&quot;, null, ENTITY, COMMA);\n        String keyProperty = null;\n        String keyColumn = null;\n        \u002F\u002F 表包含主键处理逻辑,如果不包含主键当普通字段处理\n        if (tableInfo.havePK()) {\n            if (tableInfo.getIdType() == IdType.AUTO) {\n                \u002F* 自增主键 *\u002F\n                keyGenerator = Jdbc3KeyGenerator.INSTANCE;\n                keyProperty = tableInfo.getKeyProperty();\n                keyColumn = tableInfo.getKeyColumn();\n            } else {\n                if (null != tableInfo.getKeySequence()) {\n                    keyGenerator = TableInfoHelper.genKeyGenerator(this.methodName, tableInfo, builderAssistant);\n                    keyProperty = tableInfo.getKeyProperty();\n                    keyColumn = tableInfo.getKeyColumn();\n                }\n            }\n        }\n        String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript);\n        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);\n        return this.addInsertMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource, keyGenerator, keyProperty, keyColumn);\n    }\n\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>配置 SQL 注入器\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>config\u003C\u002Fcode> 包下创建 \u003Ccode>MybatisPlusConfig\u003C\u002Fcode> 配置类：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * @Author: 张三\n * @Date: 2022-12-15 18:29\n * @Version: v1.0.0\n * @Description: TODO\n **\u002F\n@Configuration\n@MapperScan(&quot;com.mashangan.mybatisplusdemo.mapper&quot;)\npublic class MybatisPlusConfig {\n\n\n    \u002F**\n     * 自定义批量插入 SQL 注入器\n     *\u002F\n    @Bean\n    public InsertBatchSqlInjector insertBatchSqlInjector() {\n        return new InsertBatchSqlInjector();\n    }\n\n}\n\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>新建 MyBaseMapper\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>config\u003C\u002Fcode> 包下创建 \u003Ccode>MyBaseMapper\u003C\u002Fcode> 接口，让其继承自 Mybatis Plus 提供的 \u003Ccode>BaseMapper\u003C\u002Fcode>, 并定义批量插入方法：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\npublic interface MyBaseMapper&lt;T&gt; extends BaseMapper&lt;T&gt; {\n\n\t\u002F\u002F 批量插入\n    int insertBatchSomeColumn(@Param(&quot;list&quot;) List&lt;T&gt; batchList);\n\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cblockquote>\n\u003Cp>注意：方法名必须为 \u003Ccode>insertBatchSomeColumn\u003C\u002Fcode>, 和 \u003Ccode>InsertBatchSomeColumn\u003C\u002Fcode> 内部定义好的方法名保持一致。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch3>新建 UserMapper\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>mapper\u003C\u002Fcode> 包下创建 \u003Ccode>UserMapper\u003C\u002Fcode> 接口，注意继承刚刚自定义的 \u003Ccode>MyBaseMapper\u003C\u002Fcode>, 而不是 \u003Ccode>BaseMapper\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\npublic interface UserMapper extends MyBaseMapper&lt;User&gt; {\n}\n\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>测试批量插入\u003C\u002Fh2>\n\u003Cp>完成上面这些工作后，就可以使用 Mybatis Plus 提供的批量插入功能了。我们新建一个单元测试，并注入 \u003Ccode>UserMapper\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode>@Autowired\nprivate UserMapper userMapper;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>单元测试如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>@Test\nvoid testInsertBatch() {\n    List&lt;User&gt; users = new ArrayList&lt;&gt;();\n    for (int i = 0; i &lt; 3; i++) {\n        User user = new User();\n        user.setName(&quot;张三&quot; + i);\n        user.setAge(i);\n        user.setGender(1);\n        users.add(user);\n    }\n\n    userMapper.insertBatchSomeColumn(users);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>控制台实际执行 SQL 如下：\u003C\u002Fp>\n\u003Cp>\n\u003Cimg src=\"\u002Fupload\u002F167292369282647-hkCh.jpg\" loading=\"lazy\">\n\u003C\u002Fp>\n\u003Cp>可以看到这次是真实的批量插入了，舒服了~\u003C\u002Fp>\n\u003Ch2>性能对比\u003C\u002Fh2>\n\u003Cp>我们来测试一下插入 105000  条数据，分别使用 \u003Ccode>for\u003C\u002Fcode> 循环插入数据、\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入、与真实批量插入三种模式，看看耗时差距多少。\u003C\u002Fp>\n\u003Cp>这里的机器配置如下：\u003C\u002Fp>\n\u003Cp>\n\u003Cimg src=\"\u002Fupload\u002F167292550362580-Ukgp.jpg\" loading=\"lazy\">\n\u003C\u002Fp>\n\u003Ch3>\u003Ccode>for\u003C\u002Fcode> 循环插入\u003C\u002Fh3>\n\u003Cp>单元测试代码如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>@Test\nvoid testInsert1() {\n    \u002F\u002F 总耗时：722963 ms, 约 12 分钟\n    long start = System.currentTimeMillis();\n    for (int i = 0; i &lt; 105000; i++) {\n        User user = new User();\n        user.setName(&quot;张三&quot; + i);\n        user.setAge(i);\n        user.setGender(1);\n        userMapper.insert(user);\n    }\n    System.out.println(String.format(&quot;总耗时：%s ms&quot;, System.currentTimeMillis() - start));\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入\u003C\u002Fh3>\n\u003Cp>单元测试代码如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>@Test\nvoid testInsert2() {\n    \u002F\u002F 总耗时：95864 ms, 约一分钟30秒左右\n    long start = System.currentTimeMillis();\n    List&lt;User&gt; users = new ArrayList&lt;&gt;();\n    for (int i = 0; i &lt; 105000; i++) {\n        User user = new User();\n        user.setName(&quot;张三&quot; + i);\n        user.setAge(i);\n        user.setGender(1);\n        users.add(user);\n    }\n    userService.saveBatch(users);\n    System.out.println(String.format(&quot;总耗时：%s ms&quot;, System.currentTimeMillis() - start));\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>真实批量插入\u003C\u002Fh3>\n\u003Cp>注意，\u003Cstrong>真实业务场景下，也不可能会将 10 万多条记录组装成一条 SQL 进行批量插入\u003C\u002Fstrong>，因为数据库对执行 SQL 大小是有限制的（这个数值可以自行设置），还是需要分片插入，比如取 1000 条执行一次批量插入，单元测试代码如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>@Test\n    void testInsertBatch1() {\n        \u002F\u002F 总耗时：6320 ms, 约 6 秒\n        long start = System.currentTimeMillis();\n        List&lt;User&gt; users = new ArrayList&lt;&gt;();\n        for (int i = 0; i &lt; 105000; i++) {\n            User user = new User();\n            user.setName(&quot;张三&quot; + i);\n            user.setAge(i);\n            user.setGender(1);\n            users.add(user);\n        }\n\n        \u002F\u002F 分片插入（每 1000 条执行一次批量插入）\n        int batchSize = 1000;\n        int total = users.size();\n        \u002F\u002F 需要执行的次数\n        int insertTimes = total \u002F batchSize;\n        \u002F\u002F 最后一次执行需要提交的记录数（防止可能不足 1000 条）\n        int lastSize = batchSize;\n        if (total % batchSize != 0) {\n            insertTimes++;\n            lastSize = total%batchSize;\n        }\n\n        for (int j = 0; j &lt; insertTimes; j++) {\n            if (insertTimes == j+1) {\n                batchSize = lastSize;\n            }\n\n            \u002F\u002F 分片执行批量插入\n            userMapper.insertBatchSomeColumn(users.subList(j*batchSize, (j*batchSize+batchSize)));\n        }\n        System.out.println(String.format(&quot;总耗时：%s ms&quot;, System.currentTimeMillis() - start));\n    }\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>耗时对比\u003C\u002Fh3>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>方式\u003C\u002Fth>\n\u003Cth>总耗时\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>for\u003C\u002Fcode> 循环插入\u003C\u002Ftd>\n\u003Ctd>722963 ms, 约 12 分钟\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入\u003C\u002Ftd>\n\u003Ctd>95864 ms, 约一分钟30秒左右\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>真实批量插入\u003C\u002Ftd>\n\u003Ctd>6320 ms, 约 6 秒\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>耗时对比非常直观，在大批量数据新增的场景下，批量插入性能最高。\u003C\u002Fp>\n\u003Ch2>结语\u003C\u002Fh2>\n\u003Cp>本小节中，我们学习了如何通过 Mybatis Plus 的 SQL 注入器实现真实的批量插入，同时最后还对比了三种不同方式插入 10 万多数据的耗时，很直观的看到在海量数据场景下，批量插入的性能是最强的。\u003C\u002Fp>\n13:T13be6,\u003Ch2 id=\"toc-0\">前言\u003C\u002Fh2>\n\u003Cp>\u003C\u002Fp>\n\u003Cp>本小节中，我们将学习如何通过 Mybatis Plus 实现 MySQL 批量插入数据。\u003C\u002Fp>\n\u003Ch2 id=\"toc-1\">什么是批量插入？优势在哪里？\u003C\u002Fh2>\n\u003Cp>\u003Cem>先抛出一个问题：假设老板给你下了个任务，向数据库中添加 100 万条数据，并且不能耗时太久！\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>通常来说，我们向 MySQL 中新增一条记录，SQL 语句类似如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-javascript\" data-ext=\"javascript\" data-code=\"INSERT%20INTO%20%60t_user%60%20(%60name%60%2C%20%60age%60%2C%20%60gender%60)%20VALUES%20('%E5%BC%A0%E4%B8%890'%2C%200%2C%201)%3B%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-javascript\">\u003Cspan class=\"token constant\">INSERT\u003C\u002Fspan> \u003Cspan class=\"token constant\">INTO\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">t_user\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">name\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">age\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">gender\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token constant\">VALUES\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">'张三0'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>如果你需要添加 100 万条数据，就需要多次执行此语句，这就意味着频繁地 IO 操作（网络 IO、磁盘 IO），并且每一次数据库执行 SQL 都需要进行解析、优化等操作，都会导致非常耗时。\u003C\u002Fp>\n\u003Cp>幸运的是，MySQL 支持一条 SQL 语句可以批量插入多条记录，格式如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-javascript\" data-ext=\"javascript\" data-code=\"INSERT%20INTO%20%60t_user%60%20(%60name%60%2C%20%60age%60%2C%20%60gender%60)%20VALUES%20('%E5%BC%A0%E4%B8%890'%2C%200%2C%201)%2C%20('%E5%BC%A0%E4%B8%891'%2C%200%2C%201)%2C%20('%E5%BC%A0%E4%B8%893'%2C%200%2C%201)%3B%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-javascript\">\u003Cspan class=\"token constant\">INSERT\u003C\u002Fspan> \u003Cspan class=\"token constant\">INTO\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">t_user\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">name\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">age\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">gender\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token constant\">VALUES\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">'张三0'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">'张三1'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">'张三3'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>和常规的 \u003Ccode>INSERT\u003C\u002Fcode> 语句不同的是，\u003Ccode>VALUES\u003C\u002Fcode> 支持多条记录，通过 \u003Ccode>,\u003C\u002Fcode> 逗号隔开。这样，可以实现一次性插入多条记录。\u003C\u002Fp>\n\u003Cp>数据量不多的情况下，常规 \u003Ccode>INSERT\u003C\u002Fcode> 和批量插入性能差距不大，但是，一旦数量级上去后，执行耗时差距就拉开了，在后面我们会实测一下它们之间的耗时对比。\u003C\u002Fp>\n\u003Ch2 id=\"toc-2\">表与实体类\u003C\u002Fh2>\n\u003Cp>先创建一个测试表 \u003Ccode>t_user\u003C\u002Fcode>, 执行脚本如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-sql\" data-ext=\"sql\" data-code=\"DROP%20TABLE%20IF%20EXISTS%20user%3B%0A%0ACREATE%20TABLE%20%60t_user%60%20(%0A%20%20%60id%60%20bigint(20)%20UNSIGNED%20NOT%20NULL%20AUTO_INCREMENT%20COMMENT%20'%E4%B8%BB%E9%94%AEID'%2C%0A%20%20%60name%60%20varchar(30)%20NOT%20NULL%20DEFAULT%20''%20COMMENT%20'%E5%A7%93%E5%90%8D'%2C%0A%20%20%60age%60%20int(11)%20NULL%20DEFAULT%20NULL%20COMMENT%20'%E5%B9%B4%E9%BE%84'%2C%0A%20%20%60gender%60%20tinyint(2)%20NOT%20NULL%20DEFAULT%200%20COMMENT%20'%E6%80%A7%E5%88%AB%EF%BC%8C0%EF%BC%9A%E5%A5%B3%201%EF%BC%9A%E7%94%B7'%2C%0A%20%20PRIMARY%20KEY%20(%60id%60)%0A)%20COMMENT%20%3D%20'%E7%94%A8%E6%88%B7%E8%A1%A8'%3B%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-sql\">\u003Cspan class=\"token keyword\">DROP\u003C\u002Fspan> \u003Cspan class=\"token keyword\">TABLE\u003C\u002Fspan> \u003Cspan class=\"token keyword\">IF\u003C\u002Fspan> \u003Cspan class=\"token keyword\">EXISTS\u003C\u002Fspan> \u003Cspan class=\"token keyword\">user\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\n\u003Cspan class=\"token keyword\">CREATE\u003C\u002Fspan> \u003Cspan class=\"token keyword\">TABLE\u003C\u002Fspan> \u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>t_user\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\n  \u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>id\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token keyword\">bigint\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">20\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token keyword\">UNSIGNED\u003C\u002Fspan> \u003Cspan class=\"token operator\">NOT\u003C\u002Fspan> \u003Cspan class=\"token boolean\">NULL\u003C\u002Fspan> \u003Cspan class=\"token keyword\">AUTO_INCREMENT\u003C\u002Fspan> \u003Cspan class=\"token keyword\">COMMENT\u003C\u002Fspan> \u003Cspan class=\"token string\">'主键ID'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan>\n  \u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>name\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token keyword\">varchar\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">30\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">NOT\u003C\u002Fspan> \u003Cspan class=\"token boolean\">NULL\u003C\u002Fspan> \u003Cspan class=\"token keyword\">DEFAULT\u003C\u002Fspan> \u003Cspan class=\"token string\">''\u003C\u002Fspan> \u003Cspan class=\"token keyword\">COMMENT\u003C\u002Fspan> \u003Cspan class=\"token string\">'姓名'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan>\n  \u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>age\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token keyword\">int\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">11\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token boolean\">NULL\u003C\u002Fspan> \u003Cspan class=\"token keyword\">DEFAULT\u003C\u002Fspan> \u003Cspan class=\"token boolean\">NULL\u003C\u002Fspan> \u003Cspan class=\"token keyword\">COMMENT\u003C\u002Fspan> \u003Cspan class=\"token string\">'年龄'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan>\n  \u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>gender\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token keyword\">tinyint\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">2\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">NOT\u003C\u002Fspan> \u003Cspan class=\"token boolean\">NULL\u003C\u002Fspan> \u003Cspan class=\"token keyword\">DEFAULT\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan> \u003Cspan class=\"token keyword\">COMMENT\u003C\u002Fspan> \u003Cspan class=\"token string\">'性别，0：女 1：男'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan>\n  \u003Cspan class=\"token keyword\">PRIMARY\u003C\u002Fspan> \u003Cspan class=\"token keyword\">KEY\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>id\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token keyword\">COMMENT\u003C\u002Fspan> \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token string\">'用户表'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>再定义一个名为 \u003Ccode>User\u003C\u002Fcode> 实体类：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%40author%3A%20%E5%BC%A0%E4%B8%89%0A%20*%20%40from%3A%20%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%9A%E5%BC%A0%E4%B8%89%2C%20%E7%BD%91%E7%AB%99%EF%BC%9Awww.mashangan.com%0A%20*%20%40date%3A%202022-12-13%2014%3A13%0A%20*%20%40version%3A%20v1.0.0%0A%20*%20%40description%3A%20TODO%0A%20**%2F%0A%40Data%0A%40TableName(%22t_user%22)%0Apublic%20class%20User%20%7B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E4%B8%BB%E9%94%AE%20ID%2C%20%40TableId%20%E6%B3%A8%E8%A7%A3%E5%AE%9A%E4%B9%89%E5%AD%97%E6%AE%B5%E4%B8%BA%E8%A1%A8%E7%9A%84%E4%B8%BB%E9%94%AE%EF%BC%8Ctype%20%E8%A1%A8%E7%A4%BA%E4%B8%BB%E9%94%AE%E7%B1%BB%E5%9E%8B%EF%BC%8CIdType.AUTO%20%E8%A1%A8%E7%A4%BA%E9%9A%8F%E7%9D%80%E6%95%B0%E6%8D%AE%E5%BA%93%20ID%20%E8%87%AA%E5%A2%9E%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40TableId(type%20%3D%20IdType.AUTO)%0A%20%20%20%20private%20Long%20id%3B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%A7%93%E5%90%8D%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20String%20name%3B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%B9%B4%E9%BE%84%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20Integer%20age%3B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%80%A7%E5%88%AB%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20Integer%20gender%3B%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\u003C\u002Fspan>\n\u003Cspan class=\"token annotation punctuation\">@Data\u003C\u002Fspan>\n\u003Cspan class=\"token annotation punctuation\">@TableName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"t_user\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">class\u003C\u002Fspan> \u003Cspan class=\"token class-name\">User\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F**\n     * 主键 ID, @TableId 注解定义字段为表的主键，type 表示主键类型，IdType.AUTO 表示随着数据库 ID 自增\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token annotation punctuation\">@TableId\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>type \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">IdType\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token constant\">AUTO\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Long\u003C\u002Fspan> id\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F**\n     * 姓名\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> name\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F**\n     * 年龄\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Integer\u003C\u002Fspan> age\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F**\n     * 性别\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Integer\u003C\u002Fspan> gender\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cblockquote>\n\u003Cp>TIP： \u003Ccode>@Data\u003C\u002Fcode> 是 Lombok 注解，偷懒用的，加上它即可免写繁杂的 \u003Ccode>getXXX\u002FsetXXX\u003C\u002Fcode> 相关方法，不了解的小伙伴可自行搜索一下如何使用。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2 id=\"toc-3\">Mybatis Plus 伪批量插入\u003C\u002Fh2>\n\u003Cp>在前面《新增数据》\u003Cspan>\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" style=\"color: #aaa; margin-left: 3px;\" aria-hidden=\"true\" focusable=\"false\" x=\"0px\" y=\"0px\" viewBox=\"0 0 100 100\" width=\"15\" height=\"15\" class=\"icon outbound\">\u003Cpath fill=\"currentColor\" d=\"M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z\">\u003C\u002Fpath> \u003Cpolygon fill=\"currentColor\" points=\"45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9\">\u003C\u002Fpolygon>\u003C\u002Fsvg> \u003Cspan class=\"sr-only\">\u003C\u002Fspan>\u003C\u002Fspan>小节中，我们已经知道了 Mybatis Plus 内部封装的批量插入 \u003Ccode>savaBatch()\u003C\u002Fcode> 是个\u003Cstrong>假的批量插入\u003C\u002Fstrong>，示例代码如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-dockerfile\" data-ext=\"dockerfile\" data-code=\"List%3CUser%3E%20users%20%3D%20new%20ArrayList%3C%3E()%3B%0Afor%20(int%20i%20%3D%200%3B%20i%20%3C%205%3B%20i%2B%2B)%20%7B%0A%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20user.setName(%22%E5%BC%A0%E4%B8%89%22%20%2B%20i)%3B%0A%20%20%20%20user.setAge(i)%3B%0A%20%20%20%20user.setGender(1)%3B%0A%20%20%20%20users.add(user)%3B%0A%7D%0A%2F%2F%20%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%0Aboolean%20isSuccess%20%3D%20userService.saveBatch(users)%3B%0ASystem.out.println(%22isSuccess%3A%22%20%2B%20isSuccess)%3B%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-dockerfile\">List&lt;User> users = new ArrayList&lt;>();\nfor (int i = 0; i &lt; 5; i++) {\n    \u003Cspan class=\"token instruction\">\u003Cspan class=\"token keyword\">User\u003C\u002Fspan> user = new User();\u003C\u002Fspan>\n    user.setName(\"张三\" + i);\n    user.setAge(i);\n    user.setGender(1);\n    users.add(user);\n}\n\u002F\u002F 批量插入\nboolean isSuccess = userService.saveBatch(users);\nSystem.out.println(\"isSuccess:\" + isSuccess);\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>通过打印实际执行 SQL , 我们发现还是一条一条的执行 \u003Ccode>INSERT\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cp>\n\u003Cdiv class=\"img-loading\">\u003Cimg src=\"\u002Fupload\u002F167211863047181-DEdJ.jpg\" loading=\"lazy\">\u003C\u002Fdiv>\n\u003C\u002Fp>\n\u003Cp>并且还带着大家看了内部实现的源码，这种方式比起自己 \u003Ccode>for\u003C\u002Fcode> 循环一条一条 \u003Ccode>INSERT\u003C\u002Fcode> 插入数据性能要更高，原因是在\u003Cstrong>会话这块做了优化\u003C\u002Fstrong>，虽然实际执行并不是真的批量插入。\u003C\u002Fp>\n\u003Ch2 id=\"toc-4\">利用 SQL 注入器实现真的批量插入\u003C\u002Fh2>\n\u003Cp>接下来，本文就手把手带你通过 Mybatis Plus 框架的 SQL 注入器实现一个真的批量插入。\u003C\u002Fp>\n\u003Ch3 id=\"toc-5\">示例项目结构\u003C\u002Fh3>\n\u003Cp>先贴一张示例项目的结构：\u003C\u002Fp>\n\u003Cp>\n\u003Cdiv class=\"img-loading\">\u003Cimg src=\"\u002Fupload\u002F167291645197992-KIGA.jpg\" loading=\"lazy\">\u003C\u002Fdiv>\n\u003C\u002Fp>\n\u003Cp>注意看我红线标注的部分，主要关注这 4 个类与接口。\u003C\u002Fp>\n\u003Ch3 id=\"toc-6\">新建批量插入 SQL 注入器\u003C\u002Fh3>\n\u003Cp>在工程 \u003Ccode>config\u003C\u002Fcode> 目录下创建一个 SQL 注入器 \u003Ccode>InsertBatchSqlInjector\u003C\u002Fcode>  ：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%40author%3A%20%E5%BC%A0%E4%B8%89%0A%20*%20%40from%3A%20%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%9A%E5%BC%A0%E4%B8%89%2C%20%E7%BD%91%E7%AB%99%EF%BC%9Awww.mashangan.com%0A%20*%20%40date%3A%202023-01-05%2014%3A42%0A%20*%20%40version%3A%20v1.0.0%0A%20*%20%40description%3A%20%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%20SQL%20%E6%B3%A8%E5%85%A5%E5%99%A8%0A%20**%2F%0Apublic%20class%20InsertBatchSqlInjector%20extends%20DefaultSqlInjector%20%7B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20List%3CAbstractMethod%3E%20getMethodList(Class%3C%3F%3E%20mapperClass%2C%20TableInfo%20tableInfo)%20%7B%0A%20%20%20%20%09%2F%2F%20super.getMethodList()%20%E4%BF%9D%E7%95%99%20Mybatis%20Plus%20%E8%87%AA%E5%B8%A6%E7%9A%84%E6%96%B9%E6%B3%95%0A%20%20%20%20%20%20%20%20List%3CAbstractMethod%3E%20methodList%20%3D%20super.getMethodList(mapperClass%2C%20tableInfo)%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E6%B7%BB%E5%8A%A0%E8%87%AA%E5%AE%9A%E4%B9%89%E6%96%B9%E6%B3%95%EF%BC%9A%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%EF%BC%8C%E6%96%B9%E6%B3%95%E5%90%8D%E4%B8%BA%20insertBatchSomeColumn%0A%20%20%20%20%20%20%20%20methodList.add(new%20InsertBatchSomeColumn())%3B%0A%20%20%20%20%20%20%20%20return%20methodList%3B%0A%20%20%20%20%7D%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * @author: 张三\n * @date: 2023-01-05 14:42\n * @version: v1.0.0\n * @description: 批量插入 SQL 注入器\n **\u002F\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">class\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSqlInjector\u003C\u002Fspan> \u003Cspan class=\"token keyword\">extends\u003C\u002Fspan> \u003Cspan class=\"token class-name\">DefaultSqlInjector\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n\n    \u003Cspan class=\"token annotation punctuation\">@Override\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">AbstractMethod\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token function\">getMethodList\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">Class\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token operator\">?\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> mapperClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">TableInfo\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \t\u003Cspan class=\"token comment\">\u002F\u002F super.getMethodList() 保留 Mybatis Plus 自带的方法\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">AbstractMethod\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> methodList \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">super\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getMethodList\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>mapperClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token comment\">\u002F\u002F 添加自定义方法：批量插入，方法名为 insertBatchSomeColumn\u003C\u002Fspan>\n        methodList\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">add\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">return\u003C\u002Fspan> methodList\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch4 id=\"toc-7\">说说 InsertBatchSomeColumn\u003C\u002Fh4>\n\u003Cp>\u003Ccode>InsertBatchSomeColumn\u003C\u002Fcode> 是 Mybatis Plus 内部提供的默认批量插入，只不过这个方法作者只在 MySQL 数据测试过，所以没有将它作为通用方法供外部调用，注意看注释：\u003C\u002Fp>\n\u003Cp>\n\u003Cdiv class=\"img-loading\">\u003Cimg src=\"\u002Fupload\u002F167291823412173-zlfC.jpg\" loading=\"lazy\">\u003C\u002Fdiv>\n\u003C\u002Fp>\n\u003Cp>源码复制出来，如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%E6%89%B9%E9%87%8F%E6%96%B0%E5%A2%9E%E6%95%B0%E6%8D%AE%2C%E8%87%AA%E9%80%89%E5%AD%97%E6%AE%B5%20insert%0A%20*%20%3Cp%3E%20%E4%B8%8D%E5%90%8C%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E6%94%AF%E6%8C%81%E5%BA%A6%E4%B8%8D%E4%B8%80%E6%A0%B7!!!%20%20%E5%8F%AA%E5%9C%A8%20mysql%20%E4%B8%8B%E6%B5%8B%E8%AF%95%E8%BF%87!!!%20%20%E5%8F%AA%E5%9C%A8%20mysql%20%E4%B8%8B%E6%B5%8B%E8%AF%95%E8%BF%87!!!%20%20%E5%8F%AA%E5%9C%A8%20mysql%20%E4%B8%8B%E6%B5%8B%E8%AF%95%E8%BF%87!!!%20%3C%2Fp%3E%0A%20*%20%3Cp%3E%20%E9%99%A4%E4%BA%86%E4%B8%BB%E9%94%AE%E6%98%AF%20%3Cstrong%3E%20%E6%95%B0%E6%8D%AE%E5%BA%93%E8%87%AA%E5%A2%9E%E7%9A%84%E6%9C%AA%E6%B5%8B%E8%AF%95%20%3C%2Fstrong%3E%20%E5%A4%96%E7%90%86%E8%AE%BA%E4%B8%8A%E9%83%BD%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8!!!%20%3C%2Fp%3E%0A%20*%20%3Cp%3E%20%E5%A6%82%E6%9E%9C%E4%BD%A0%E4%BD%BF%E7%94%A8%E8%87%AA%E5%A2%9E%E6%9C%89%E6%8A%A5%E9%94%99%E6%88%96%E4%B8%BB%E9%94%AE%E5%80%BC%E6%97%A0%E6%B3%95%E5%9B%9E%E5%86%99%E5%88%B0entity%2C%E5%B0%B1%E4%B8%8D%E8%A6%81%E8%B7%91%E6%9D%A5%E9%97%AE%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BA%86%2C%E5%9B%A0%E4%B8%BA%E6%88%91%E4%B9%9F%E4%B8%8D%E7%9F%A5%E9%81%93!!!%20%3C%2Fp%3E%0A%20*%20%3Cp%3E%0A%20*%20%E8%87%AA%E5%B7%B1%E7%9A%84%E9%80%9A%E7%94%A8%20mapper%20%E5%A6%82%E4%B8%8B%E4%BD%BF%E7%94%A8%3A%0A%20*%20%3Cpre%3E%0A%20*%20int%20insertBatchSomeColumn(List%3CT%3E%20entityList)%3B%0A%20*%20%3C%2Fpre%3E%0A%20*%20%3C%2Fp%3E%0A%20*%0A%20*%20%3Cli%3E%20%E6%B3%A8%E6%84%8F%3A%20%E8%BF%99%E6%98%AF%E8%87%AA%E9%80%89%E5%AD%97%E6%AE%B5%20insert%20!!%2C%E5%A6%82%E6%9E%9C%E4%B8%AA%E5%88%AB%E5%AD%97%E6%AE%B5%E5%9C%A8%20entity%20%E9%87%8C%E4%B8%BA%20null%20%E4%BD%86%E6%98%AF%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E6%9C%89%E9%85%8D%E7%BD%AE%E9%BB%98%E8%AE%A4%E5%80%BC%2C%20insert%20%E5%90%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AD%97%E6%AE%B5%E6%98%AF%E4%B8%BA%20null%20%E8%80%8C%E4%B8%8D%E6%98%AF%E9%BB%98%E8%AE%A4%E5%80%BC%20%3C%2Fli%3E%0A%20*%0A%20*%20%3Cp%3E%0A%20*%20%E5%B8%B8%E7%94%A8%E7%9A%84%20%7B%40link%20Predicate%7D%3A%0A%20*%20%3C%2Fp%3E%0A%20*%0A%20*%20%3Cli%3E%20%E4%BE%8B1%3A%20t%20-%3E%20!t.isLogicDelete()%20%2C%20%E8%A1%A8%E7%A4%BA%E4%B8%8D%E8%A6%81%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4%E5%AD%97%E6%AE%B5%20%3C%2Fli%3E%0A%20*%20%3Cli%3E%20%E4%BE%8B2%3A%20t%20-%3E%20!t.getProperty().equals(%22version%22)%20%2C%20%E8%A1%A8%E7%A4%BA%E4%B8%8D%E8%A6%81%E5%AD%97%E6%AE%B5%E5%90%8D%E4%B8%BA%20version%20%E7%9A%84%E5%AD%97%E6%AE%B5%20%3C%2Fli%3E%0A%20*%20%3Cli%3E%20%E4%BE%8B3%3A%20t%20-%3E%20t.getFieldFill()%20!%3D%20FieldFill.UPDATE)%20%2C%20%E8%A1%A8%E7%A4%BA%E4%B8%8D%E8%A6%81%E5%A1%AB%E5%85%85%E7%AD%96%E7%95%A5%E4%B8%BA%20UPDATE%20%E7%9A%84%E5%AD%97%E6%AE%B5%20%3C%2Fli%3E%0A%20*%0A%20*%20%40author%20miemie%0A%20*%20%40since%202018-11-29%0A%20*%2F%0A%0A%40SuppressWarnings(%22serial%22)%0Apublic%20class%20InsertBatchSomeColumn%20extends%20AbstractMethod%20%7B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%AD%97%E6%AE%B5%E7%AD%9B%E9%80%89%E6%9D%A1%E4%BB%B6%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Setter%0A%20%20%20%20%40Accessors(chain%20%3D%20true)%0A%20%20%20%20private%20Predicate%3CTableFieldInfo%3E%20predicate%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%BB%98%E8%AE%A4%E6%96%B9%E6%B3%95%E5%90%8D%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20InsertBatchSomeColumn()%20%7B%0A%20%20%20%20%09%2F%2F%20%E6%96%B9%E6%B3%95%E5%90%8D%0A%20%20%20%20%20%20%20%20super(%22insertBatchSomeColumn%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%BB%98%E8%AE%A4%E6%96%B9%E6%B3%95%E5%90%8D%0A%20%20%20%20%20*%0A%20%20%20%20%20*%20%40param%20predicate%20%E5%AD%97%E6%AE%B5%E7%AD%9B%E9%80%89%E6%9D%A1%E4%BB%B6%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20InsertBatchSomeColumn(Predicate%3CTableFieldInfo%3E%20predicate)%20%7B%0A%20%20%20%20%20%20%20%20super(%22insertBatchSomeColumn%22)%3B%0A%20%20%20%20%20%20%20%20this.predicate%20%3D%20predicate%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%40param%20name%20%20%20%20%20%20%E6%96%B9%E6%B3%95%E5%90%8D%0A%20%20%20%20%20*%20%40param%20predicate%20%E5%AD%97%E6%AE%B5%E7%AD%9B%E9%80%89%E6%9D%A1%E4%BB%B6%0A%20%20%20%20%20*%20%40since%203.5.0%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20InsertBatchSomeColumn(String%20name%2C%20Predicate%3CTableFieldInfo%3E%20predicate)%20%7B%0A%20%20%20%20%20%20%20%20super(name)%3B%0A%20%20%20%20%20%20%20%20this.predicate%20%3D%20predicate%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40SuppressWarnings(%22Duplicates%22)%0A%20%20%20%20%40Override%0A%20%20%20%20public%20MappedStatement%20injectMappedStatement(Class%3C%3F%3E%20mapperClass%2C%20Class%3C%3F%3E%20modelClass%2C%20TableInfo%20tableInfo)%20%7B%0A%20%20%20%20%20%20%20%20KeyGenerator%20keyGenerator%20%3D%20NoKeyGenerator.INSTANCE%3B%0A%20%20%20%20%20%20%20%20SqlMethod%20sqlMethod%20%3D%20SqlMethod.INSERT_ONE%3B%0A%20%20%20%20%20%20%20%20List%3CTableFieldInfo%3E%20fieldList%20%3D%20tableInfo.getFieldList()%3B%0A%20%20%20%20%20%20%20%20String%20insertSqlColumn%20%3D%20tableInfo.getKeyInsertSqlColumn(true%2C%20false)%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20this.filterTableFieldInfo(fieldList%2C%20predicate%2C%20TableFieldInfo%3A%3AgetInsertSqlColumn%2C%20EMPTY)%3B%0A%20%20%20%20%20%20%20%20String%20columnScript%20%3D%20LEFT_BRACKET%20%2B%20insertSqlColumn.substring(0%2C%20insertSqlColumn.length()%20-%201)%20%2B%20RIGHT_BRACKET%3B%0A%20%20%20%20%20%20%20%20String%20insertSqlProperty%20%3D%20tableInfo.getKeyInsertSqlProperty(true%2C%20ENTITY_DOT%2C%20false)%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20this.filterTableFieldInfo(fieldList%2C%20predicate%2C%20i%20-%3E%20i.getInsertSqlProperty(ENTITY_DOT)%2C%20EMPTY)%3B%0A%20%20%20%20%20%20%20%20insertSqlProperty%20%3D%20LEFT_BRACKET%20%2B%20insertSqlProperty.substring(0%2C%20insertSqlProperty.length()%20-%201)%20%2B%20RIGHT_BRACKET%3B%0A%20%20%20%20%20%20%20%20String%20valuesScript%20%3D%20SqlScriptUtils.convertForeach(insertSqlProperty%2C%20%22list%22%2C%20null%2C%20ENTITY%2C%20COMMA)%3B%0A%20%20%20%20%20%20%20%20String%20keyProperty%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20String%20keyColumn%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E8%A1%A8%E5%8C%85%E5%90%AB%E4%B8%BB%E9%94%AE%E5%A4%84%E7%90%86%E9%80%BB%E8%BE%91%2C%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%8C%85%E5%90%AB%E4%B8%BB%E9%94%AE%E5%BD%93%E6%99%AE%E9%80%9A%E5%AD%97%E6%AE%B5%E5%A4%84%E7%90%86%0A%20%20%20%20%20%20%20%20if%20(tableInfo.havePK())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(tableInfo.getIdType()%20%3D%3D%20IdType.AUTO)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F*%20%E8%87%AA%E5%A2%9E%E4%B8%BB%E9%94%AE%20*%2F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyGenerator%20%3D%20Jdbc3KeyGenerator.INSTANCE%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyProperty%20%3D%20tableInfo.getKeyProperty()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyColumn%20%3D%20tableInfo.getKeyColumn()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20tableInfo.getKeySequence())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyGenerator%20%3D%20TableInfoHelper.genKeyGenerator(this.methodName%2C%20tableInfo%2C%20builderAssistant)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyProperty%20%3D%20tableInfo.getKeyProperty()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyColumn%20%3D%20tableInfo.getKeyColumn()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20String%20sql%20%3D%20String.format(sqlMethod.getSql()%2C%20tableInfo.getTableName()%2C%20columnScript%2C%20valuesScript)%3B%0A%20%20%20%20%20%20%20%20SqlSource%20sqlSource%20%3D%20languageDriver.createSqlSource(configuration%2C%20sql%2C%20modelClass)%3B%0A%20%20%20%20%20%20%20%20return%20this.addInsertMappedStatement(mapperClass%2C%20modelClass%2C%20getMethod(sqlMethod)%2C%20sqlSource%2C%20keyGenerator%2C%20keyProperty%2C%20keyColumn)%3B%0A%20%20%20%20%7D%0A%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * 批量新增数据,自选字段 insert\n * &lt;p> 不同的数据库支持度不一样!!!  只在 mysql 下测试过!!!  只在 mysql 下测试过!!!  只在 mysql 下测试过!!! &lt;\u002Fp>\n * &lt;p> 除了主键是 &lt;strong> 数据库自增的未测试 &lt;\u002Fstrong> 外理论上都可以使用!!! &lt;\u002Fp>\n * &lt;p> 如果你使用自增有报错或主键值无法回写到entity,就不要跑来问为什么了,因为我也不知道!!! &lt;\u002Fp>\n * &lt;p>\n * 自己的通用 mapper 如下使用:\n * &lt;pre>\n * int insertBatchSomeColumn(List&lt;T> entityList);\n * &lt;\u002Fpre>\n * &lt;\u002Fp>\n *\n * &lt;li> 注意: 这是自选字段 insert !!,如果个别字段在 entity 里为 null 但是数据库中有配置默认值, insert 后数据库字段是为 null 而不是默认值 &lt;\u002Fli>\n *\n * &lt;p>\n * 常用的 {@link Predicate}:\n * &lt;\u002Fp>\n *\n * &lt;li> 例1: t -> !t.isLogicDelete() , 表示不要逻辑删除字段 &lt;\u002Fli>\n * &lt;li> 例2: t -> !t.getProperty().equals(\"version\") , 表示不要字段名为 version 的字段 &lt;\u002Fli>\n * &lt;li> 例3: t -> t.getFieldFill() != FieldFill.UPDATE) , 表示不要填充策略为 UPDATE 的字段 &lt;\u002Fli>\n *\n * @author miemie\n * @since 2018-11-29\n *\u002F\u003C\u002Fspan>\n\n\u003Cspan class=\"token annotation punctuation\">@SuppressWarnings\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"serial\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">class\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSomeColumn\u003C\u002Fspan> \u003Cspan class=\"token keyword\">extends\u003C\u002Fspan> \u003Cspan class=\"token class-name\">AbstractMethod\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n\n    \u003Cspan class=\"token comment\">\u002F**\n     * 字段筛选条件\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token annotation punctuation\">@Setter\u003C\u002Fspan>\n    \u003Cspan class=\"token annotation punctuation\">@Accessors\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>chain \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token boolean\">true\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Predicate\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">TableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\n    \u003Cspan class=\"token comment\">\u002F**\n     * 默认方法名\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \t\u003Cspan class=\"token comment\">\u002F\u002F 方法名\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">super\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"insertBatchSomeColumn\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n    \u003Cspan class=\"token comment\">\u002F**\n     * 默认方法名\n     *\n     * @param predicate 字段筛选条件\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">Predicate\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">TableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">super\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"insertBatchSomeColumn\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>predicate \u003Cspan class=\"token operator\">=\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n    \u003Cspan class=\"token comment\">\u002F**\n     * @param name      方法名\n     * @param predicate 字段筛选条件\n     * @since 3.5.0\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">String\u003C\u002Fspan> name\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Predicate\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">TableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">super\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>name\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>predicate \u003Cspan class=\"token operator\">=\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n    \u003Cspan class=\"token annotation punctuation\">@SuppressWarnings\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"Duplicates\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n    \u003Cspan class=\"token annotation punctuation\">@Override\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">MappedStatement\u003C\u002Fspan> \u003Cspan class=\"token function\">injectMappedStatement\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">Class\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token operator\">?\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> mapperClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Class\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token operator\">?\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> modelClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">TableInfo\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">KeyGenerator\u003C\u002Fspan> keyGenerator \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">NoKeyGenerator\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token constant\">INSTANCE\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">SqlMethod\u003C\u002Fspan> sqlMethod \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">SqlMethod\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token constant\">INSERT_ONE\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">TableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> fieldList \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getFieldList\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> insertSqlColumn \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyInsertSqlColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token boolean\">true\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token boolean\">false\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan>\n            \u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">filterTableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>fieldList\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">TableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token operator\">::\u003C\u002Fspan>\u003Cspan class=\"token function\">getInsertSqlColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token constant\">EMPTY\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> columnScript \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token constant\">LEFT_BRACKET\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> insertSqlColumn\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">substring\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> insertSqlColumn\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">length\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">-\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> \u003Cspan class=\"token constant\">RIGHT_BRACKET\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> insertSqlProperty \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyInsertSqlProperty\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token boolean\">true\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token constant\">ENTITY_DOT\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token boolean\">false\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan>\n            \u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">filterTableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>fieldList\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> i \u003Cspan class=\"token operator\">->\u003C\u002Fspan> i\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getInsertSqlProperty\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token constant\">ENTITY_DOT\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token constant\">EMPTY\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        insertSqlProperty \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token constant\">LEFT_BRACKET\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> insertSqlProperty\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">substring\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> insertSqlProperty\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">length\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">-\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> \u003Cspan class=\"token constant\">RIGHT_BRACKET\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> valuesScript \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">SqlScriptUtils\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">convertForeach\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>insertSqlProperty\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token string\">\"list\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token keyword\">null\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token constant\">ENTITY\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token constant\">COMMA\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> keyProperty \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">null\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> keyColumn \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">null\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token comment\">\u002F\u002F 表包含主键处理逻辑,如果不包含主键当普通字段处理\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">if\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">havePK\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n            \u003Cspan class=\"token keyword\">if\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getIdType\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">==\u003C\u002Fspan> \u003Cspan class=\"token class-name\">IdType\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token constant\">AUTO\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n                \u003Cspan class=\"token comment\">\u002F* 自增主键 *\u002F\u003C\u002Fspan>\n                keyGenerator \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Jdbc3KeyGenerator\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token constant\">INSTANCE\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n                keyProperty \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyProperty\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n                keyColumn \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan> \u003Cspan class=\"token keyword\">else\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n                \u003Cspan class=\"token keyword\">if\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">null\u003C\u002Fspan> \u003Cspan class=\"token operator\">!=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeySequence\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n                    keyGenerator \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">TableInfoHelper\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">genKeyGenerator\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>methodName\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> builderAssistant\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n                    keyProperty \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyProperty\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n                    keyColumn \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n                \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n            \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n        \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> sql \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">String\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">format\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>sqlMethod\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getSql\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getTableName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> columnScript\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> valuesScript\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">SqlSource\u003C\u002Fspan> sqlSource \u003Cspan class=\"token operator\">=\u003C\u002Fspan> languageDriver\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">createSqlSource\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>configuration\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> sql\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> modelClass\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">return\u003C\u002Fspan> \u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">addInsertMappedStatement\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>mapperClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> modelClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token function\">getMethod\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>sqlMethod\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> sqlSource\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> keyGenerator\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> keyProperty\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> keyColumn\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch3 id=\"toc-8\">配置 SQL 注入器\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>config\u003C\u002Fcode> 包下创建 \u003Ccode>MybatisPlusConfig\u003C\u002Fcode> 配置类：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%40Author%3A%20%E5%BC%A0%E4%B8%89%0A%20*%20%40From%3A%20%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%9A%E5%BC%A0%E4%B8%89%2C%20%E7%BD%91%E7%AB%99%EF%BC%9Awww.mashangan.com%0A%20*%20%40Date%3A%202022-12-15%2018%3A29%0A%20*%20%40Version%3A%20v1.0.0%0A%20*%20%40Description%3A%20TODO%0A%20**%2F%0A%40Configuration%0A%40MapperScan(%22com.mashangan.mybatisplusdemo.mapper%22)%0Apublic%20class%20MybatisPlusConfig%20%7B%0A%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%87%AA%E5%AE%9A%E4%B9%89%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%20SQL%20%E6%B3%A8%E5%85%A5%E5%99%A8%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20InsertBatchSqlInjector%20insertBatchSqlInjector()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20InsertBatchSqlInjector()%3B%0A%20%20%20%20%7D%0A%0A%7D%0A%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * @Author: 张三\n * @Date: 2022-12-15 18:29\n * @Version: v1.0.0\n * @Description: TODO\n **\u002F\u003C\u002Fspan>\n\u003Cspan class=\"token annotation punctuation\">@Configuration\u003C\u002Fspan>\n\u003Cspan class=\"token annotation punctuation\">@MapperScan\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"com.mashangan.mybatisplusdemo.mapper\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">class\u003C\u002Fspan> \u003Cspan class=\"token class-name\">MybatisPlusConfig\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n\n\n    \u003Cspan class=\"token comment\">\u002F**\n     * 自定义批量插入 SQL 注入器\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token annotation punctuation\">@Bean\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSqlInjector\u003C\u002Fspan> \u003Cspan class=\"token function\">insertBatchSqlInjector\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">return\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSqlInjector\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch3 id=\"toc-9\">新建 MyBaseMapper\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>config\u003C\u002Fcode> 包下创建 \u003Ccode>MyBaseMapper\u003C\u002Fcode> 接口，让其继承自 Mybatis Plus 提供的 \u003Ccode>BaseMapper\u003C\u002Fcode>, 并定义批量插入方法：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%40author%3A%20%E5%BC%A0%E4%B8%89%0A%20*%20%40from%3A%20%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%9A%E5%BC%A0%E4%B8%89%2C%20%E7%BD%91%E7%AB%99%EF%BC%9Awww.mashangan.com%0A%20*%20%40date%3A%202022-12-13%2014%3A13%0A%20*%20%40version%3A%20v1.0.0%0A%20*%20%40description%3A%20TODO%0A%20**%2F%0Apublic%20interface%20MyBaseMapper%3CT%3E%20extends%20BaseMapper%3CT%3E%20%7B%0A%0A%09%2F%2F%20%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%0A%20%20%20%20int%20insertBatchSomeColumn(%40Param(%22list%22)%20List%3CT%3E%20batchList)%3B%0A%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">interface\u003C\u002Fspan> \u003Cspan class=\"token class-name\">MyBaseMapper\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">T\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token keyword\">extends\u003C\u002Fspan> \u003Cspan class=\"token class-name\">BaseMapper\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">T\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n\n\t\u003Cspan class=\"token comment\">\u002F\u002F 批量插入\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">int\u003C\u002Fspan> \u003Cspan class=\"token function\">insertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token annotation punctuation\">@Param\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"list\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">T\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> batchList\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cblockquote>\n\u003Cp>注意：方法名必须为 \u003Ccode>insertBatchSomeColumn\u003C\u002Fcode>, 和 \u003Ccode>InsertBatchSomeColumn\u003C\u002Fcode> 内部定义好的方法名保持一致。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch3 id=\"toc-10\">新建 UserMapper\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>mapper\u003C\u002Fcode> 包下创建 \u003Ccode>UserMapper\u003C\u002Fcode> 接口，注意继承刚刚自定义的 \u003Ccode>MyBaseMapper\u003C\u002Fcode>, 而不是 \u003Ccode>BaseMapper\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%40author%3A%20%E5%BC%A0%E4%B8%89%0A%20*%20%40from%3A%20%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%9A%E5%BC%A0%E4%B8%89%2C%20%E7%BD%91%E7%AB%99%EF%BC%9Awww.mashangan.com%0A%20*%20%40date%3A%202022-12-13%2014%3A13%0A%20*%20%40version%3A%20v1.0.0%0A%20*%20%40description%3A%20TODO%0A%20**%2F%0Apublic%20interface%20UserMapper%20extends%20MyBaseMapper%3CUser%3E%20%7B%0A%7D%0A%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">interface\u003C\u002Fspan> \u003Cspan class=\"token class-name\">UserMapper\u003C\u002Fspan> \u003Cspan class=\"token keyword\">extends\u003C\u002Fspan> \u003Cspan class=\"token class-name\">MyBaseMapper\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch2 id=\"toc-11\">测试批量插入\u003C\u002Fh2>\n\u003Cp>完成上面这些工作后，就可以使用 Mybatis Plus 提供的批量插入功能了。我们新建一个单元测试，并注入 \u003Ccode>UserMapper\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%40Autowired%0Aprivate%20UserMapper%20userMapper%3B%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token annotation punctuation\">@Autowired\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">UserMapper\u003C\u002Fspan> userMapper\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>单元测试如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%40Test%0Avoid%20testInsertBatch()%20%7B%0A%20%20%20%20List%3CUser%3E%20users%20%3D%20new%20ArrayList%3C%3E()%3B%0A%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%203%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20%20%20%20%20user.setName(%22%E5%BC%A0%E4%B8%89%22%20%2B%20i)%3B%0A%20%20%20%20%20%20%20%20user.setAge(i)%3B%0A%20%20%20%20%20%20%20%20user.setGender(1)%3B%0A%20%20%20%20%20%20%20%20users.add(user)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20userMapper.insertBatchSomeColumn(users)%3B%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token annotation punctuation\">@Test\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">void\u003C\u002Fspan> \u003Cspan class=\"token function\">testInsertBatch\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> users \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">ArrayList\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">for\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">int\u003C\u002Fspan> i \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i \u003Cspan class=\"token operator\">&lt;\u003C\u002Fspan> \u003Cspan class=\"token number\">3\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">User\u003C\u002Fspan> user \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"张三\"\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setAge\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setGender\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        users\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">add\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>user\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n    userMapper\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">insertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>users\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>控制台实际执行 SQL 如下：\u003C\u002Fp>\n\u003Cp>\n\u003Cdiv class=\"img-loading\">\u003Cimg src=\"\u002Fupload\u002F167292369282647-hkCh.jpg\" loading=\"lazy\">\u003C\u002Fdiv>\n\u003C\u002Fp>\n\u003Cp>可以看到这次是真实的批量插入了，舒服了~\u003C\u002Fp>\n\u003Ch2 id=\"toc-12\">性能对比\u003C\u002Fh2>\n\u003Cp>我们来测试一下插入 105000  条数据，分别使用 \u003Ccode>for\u003C\u002Fcode> 循环插入数据、\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入、与真实批量插入三种模式，看看耗时差距多少。\u003C\u002Fp>\n\u003Cp>这里的机器配置如下：\u003C\u002Fp>\n\u003Cp>\n\u003Cdiv class=\"img-loading\">\u003Cimg src=\"\u002Fupload\u002F167292550362580-Ukgp.jpg\" loading=\"lazy\">\u003C\u002Fdiv>\n\u003C\u002Fp>\n\u003Ch3 id=\"toc-13\">\u003Ccode>for\u003C\u002Fcode> 循环插入\u003C\u002Fh3>\n\u003Cp>单元测试代码如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%40Test%0Avoid%20testInsert1()%20%7B%0A%20%20%20%20%2F%2F%20%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A722963%20ms%2C%20%E7%BA%A6%2012%20%E5%88%86%E9%92%9F%0A%20%20%20%20long%20start%20%3D%20System.currentTimeMillis()%3B%0A%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20105000%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20%20%20%20%20user.setName(%22%E5%BC%A0%E4%B8%89%22%20%2B%20i)%3B%0A%20%20%20%20%20%20%20%20user.setAge(i)%3B%0A%20%20%20%20%20%20%20%20user.setGender(1)%3B%0A%20%20%20%20%20%20%20%20userMapper.insert(user)%3B%0A%20%20%20%20%7D%0A%20%20%20%20System.out.println(String.format(%22%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A%25s%20ms%22%2C%20System.currentTimeMillis()%20-%20start))%3B%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token annotation punctuation\">@Test\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">void\u003C\u002Fspan> \u003Cspan class=\"token function\">testInsert1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F\u002F 总耗时：722963 ms, 约 12 分钟\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">long\u003C\u002Fspan> start \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">for\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">int\u003C\u002Fspan> i \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i \u003Cspan class=\"token operator\">&lt;\u003C\u002Fspan> \u003Cspan class=\"token number\">105000\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">User\u003C\u002Fspan> user \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"张三\"\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setAge\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setGender\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        userMapper\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">insert\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>user\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n    \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>out\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">println\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">String\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">format\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"总耗时：%s ms\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">-\u003C\u002Fspan> start\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch3 id=\"toc-14\">\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入\u003C\u002Fh3>\n\u003Cp>单元测试代码如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%40Test%0Avoid%20testInsert2()%20%7B%0A%20%20%20%20%2F%2F%20%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A95864%20ms%2C%20%E7%BA%A6%E4%B8%80%E5%88%86%E9%92%9F30%E7%A7%92%E5%B7%A6%E5%8F%B3%0A%20%20%20%20long%20start%20%3D%20System.currentTimeMillis()%3B%0A%20%20%20%20List%3CUser%3E%20users%20%3D%20new%20ArrayList%3C%3E()%3B%0A%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20105000%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20%20%20%20%20user.setName(%22%E5%BC%A0%E4%B8%89%22%20%2B%20i)%3B%0A%20%20%20%20%20%20%20%20user.setAge(i)%3B%0A%20%20%20%20%20%20%20%20user.setGender(1)%3B%0A%20%20%20%20%20%20%20%20users.add(user)%3B%0A%20%20%20%20%7D%0A%20%20%20%20userService.saveBatch(users)%3B%0A%20%20%20%20System.out.println(String.format(%22%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A%25s%20ms%22%2C%20System.currentTimeMillis()%20-%20start))%3B%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token annotation punctuation\">@Test\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">void\u003C\u002Fspan> \u003Cspan class=\"token function\">testInsert2\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F\u002F 总耗时：95864 ms, 约一分钟30秒左右\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">long\u003C\u002Fspan> start \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> users \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">ArrayList\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">for\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">int\u003C\u002Fspan> i \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i \u003Cspan class=\"token operator\">&lt;\u003C\u002Fspan> \u003Cspan class=\"token number\">105000\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">User\u003C\u002Fspan> user \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"张三\"\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setAge\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setGender\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        users\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">add\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>user\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n    userService\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">saveBatch\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>users\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>out\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">println\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">String\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">format\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"总耗时：%s ms\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">-\u003C\u002Fspan> start\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch3 id=\"toc-15\">真实批量插入\u003C\u002Fh3>\n\u003Cp>注意，\u003Cstrong>真实业务场景下，也不可能会将 10 万多条记录组装成一条 SQL 进行批量插入\u003C\u002Fstrong>，因为数据库对执行 SQL 大小是有限制的（这个数值可以自行设置），还是需要分片插入，比如取 1000 条执行一次批量插入，单元测试代码如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%40Test%0A%20%20%20%20void%20testInsertBatch1()%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A6320%20ms%2C%20%E7%BA%A6%206%20%E7%A7%92%0A%20%20%20%20%20%20%20%20long%20start%20%3D%20System.currentTimeMillis()%3B%0A%20%20%20%20%20%20%20%20List%3CUser%3E%20users%20%3D%20new%20ArrayList%3C%3E()%3B%0A%20%20%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20105000%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20user.setName(%22%E5%BC%A0%E4%B8%89%22%20%2B%20i)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20user.setAge(i)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20user.setGender(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20users.add(user)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20%E5%88%86%E7%89%87%E6%8F%92%E5%85%A5%EF%BC%88%E6%AF%8F%201000%20%E6%9D%A1%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AC%A1%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%EF%BC%89%0A%20%20%20%20%20%20%20%20int%20batchSize%20%3D%201000%3B%0A%20%20%20%20%20%20%20%20int%20total%20%3D%20users.size()%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E9%9C%80%E8%A6%81%E6%89%A7%E8%A1%8C%E7%9A%84%E6%AC%A1%E6%95%B0%0A%20%20%20%20%20%20%20%20int%20insertTimes%20%3D%20total%20%2F%20batchSize%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E6%89%A7%E8%A1%8C%E9%9C%80%E8%A6%81%E6%8F%90%E4%BA%A4%E7%9A%84%E8%AE%B0%E5%BD%95%E6%95%B0%EF%BC%88%E9%98%B2%E6%AD%A2%E5%8F%AF%E8%83%BD%E4%B8%8D%E8%B6%B3%201000%20%E6%9D%A1%EF%BC%89%0A%20%20%20%20%20%20%20%20int%20lastSize%20%3D%20batchSize%3B%0A%20%20%20%20%20%20%20%20if%20(total%20%25%20batchSize%20!%3D%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20insertTimes%2B%2B%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20lastSize%20%3D%20total%25batchSize%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20for%20(int%20j%20%3D%200%3B%20j%20%3C%20insertTimes%3B%20j%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(insertTimes%20%3D%3D%20j%2B1)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20batchSize%20%3D%20lastSize%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E5%88%86%E7%89%87%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%0A%20%20%20%20%20%20%20%20%20%20%20%20userMapper.insertBatchSomeColumn(users.subList(j*batchSize%2C%20(j*batchSize%2BbatchSize)))%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println(String.format(%22%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A%25s%20ms%22%2C%20System.currentTimeMillis()%20-%20start))%3B%0A%20%20%20%20%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token annotation punctuation\">@Test\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">void\u003C\u002Fspan> \u003Cspan class=\"token function\">testInsertBatch1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token comment\">\u002F\u002F 总耗时：6320 ms, 约 6 秒\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">long\u003C\u002Fspan> start \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> users \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">ArrayList\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">for\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">int\u003C\u002Fspan> i \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i \u003Cspan class=\"token operator\">&lt;\u003C\u002Fspan> \u003Cspan class=\"token number\">105000\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n            \u003Cspan class=\"token class-name\">User\u003C\u002Fspan> user \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"张三\"\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setAge\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setGender\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            users\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">add\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>user\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n        \u003Cspan class=\"token comment\">\u002F\u002F 分片插入（每 1000 条执行一次批量插入）\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">int\u003C\u002Fspan> batchSize \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">1000\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">int\u003C\u002Fspan> total \u003Cspan class=\"token operator\">=\u003C\u002Fspan> users\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">size\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token comment\">\u002F\u002F 需要执行的次数\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">int\u003C\u002Fspan> insertTimes \u003Cspan class=\"token operator\">=\u003C\u002Fspan> total \u003Cspan class=\"token operator\">\u002F\u003C\u002Fspan> batchSize\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token comment\">\u002F\u002F 最后一次执行需要提交的记录数（防止可能不足 1000 条）\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">int\u003C\u002Fspan> lastSize \u003Cspan class=\"token operator\">=\u003C\u002Fspan> batchSize\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">if\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>total \u003Cspan class=\"token operator\">%\u003C\u002Fspan> batchSize \u003Cspan class=\"token operator\">!=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n            insertTimes\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            lastSize \u003Cspan class=\"token operator\">=\u003C\u002Fspan> total\u003Cspan class=\"token operator\">%\u003C\u002Fspan>batchSize\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n        \u003Cspan class=\"token keyword\">for\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">int\u003C\u002Fspan> j \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> j \u003Cspan class=\"token operator\">&lt;\u003C\u002Fspan> insertTimes\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> j\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n            \u003Cspan class=\"token keyword\">if\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>insertTimes \u003Cspan class=\"token operator\">==\u003C\u002Fspan> j\u003Cspan class=\"token operator\">+\u003C\u002Fspan>\u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n                batchSize \u003Cspan class=\"token operator\">=\u003C\u002Fspan> lastSize\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n            \u003Cspan class=\"token comment\">\u002F\u002F 分片执行批量插入\u003C\u002Fspan>\n            userMapper\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">insertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>users\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">subList\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>j\u003Cspan class=\"token operator\">*\u003C\u002Fspan>batchSize\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>j\u003Cspan class=\"token operator\">*\u003C\u002Fspan>batchSize\u003Cspan class=\"token operator\">+\u003C\u002Fspan>batchSize\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>out\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">println\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">String\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">format\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"总耗时：%s ms\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">-\u003C\u002Fspan> start\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch3 id=\"toc-16\">耗时对比\u003C\u002Fh3>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>方式\u003C\u002Fth>\n\u003Cth>总耗时\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>for\u003C\u002Fcode> 循环插入\u003C\u002Ftd>\n\u003Ctd>722963 ms, 约 12 分钟\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入\u003C\u002Ftd>\n\u003Ctd>95864 ms, 约一分钟30秒左右\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>真实批量插入\u003C\u002Ftd>\n\u003Ctd>6320 ms, 约 6 秒\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>耗时对比非常直观，在大批量数据新增的场景下，批量插入性能最高。\u003C\u002Fp>\n\u003Ch2 id=\"toc-17\">结语\u003C\u002Fh2>\n\u003Cp>本小节中，我们学习了如何通过 Mybatis Plus 的 SQL 注入器实现真实的批量插入，同时最后还对比了三种不同方式插入 10 万多数据的耗时，很直观的看到在海量数据场景下，批量插入的性能是最强的。\u003C\u002Fp>","\u003Cp>大家好。\u003C\u002Fp>\n\u003Cp>本小节中，我们将学习如何通过 Mybatis Plus 实现 MySQL 批量插入数据。\u003C\u002Fp>\n\u003Ch2>什么是批量插入？优势在哪里？\u003C\u002Fh2>\n\u003Cp>\u003Cem>先抛出一个问题：假设老板给你下了个任务，向数据库中添加 100 万条数据，并且不能耗时太久！\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>通常来说，我们向 MySQL 中新增一条记录，SQL 语句类似如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>INSERT INTO `t_user` (`name`, `age`, `gender`) VALUES ('张三0', 0, 1);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>如果你需要添加 100 万条数据，就需要多次执行此语句，这就意味着频繁地 IO 操作（网络 IO、磁盘 IO），并且每一次数据库执行 SQL 都需要进行解析、优化等操作，都会导致非常耗时。\u003C\u002Fp>\n\u003Cp>幸运的是，MySQL 支持一条 SQL 语句可以批量插入多条记录，格式如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>INSERT INTO `t_user` (`name`, `age`, `gender`) VALUES ('张三0', 0, 1), ('张三1', 0, 1), ('张三3', 0, 1);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>和常规的 \u003Ccode>INSERT\u003C\u002Fcode> 语句不同的是，\u003Ccode>VALUES\u003C\u002Fcode> 支持多条记录，通过 \u003Ccode>,\u003C\u002Fcode> 逗号隔开。这样，可以实现一次性插入多条记录。\u003C\u002Fp>\n\u003Cp>数据量不多的情况下，常规 \u003Ccode>INSERT\u003C\u002Fcode> 和批量插入性能差距不大，但是，一旦数量级上去后，执行耗时差距就拉开了，在后面我们会实测一下它们之间的耗时对比。\u003C\u002Fp>\n\u003Ch2>表与实体类\u003C\u002Fh2>\n\u003Cp>先创建一个测试表 \u003Ccode>t_user\u003C\u002Fcode>, 执行脚本如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>DROP TABLE IF EXISTS user;\n\nCREATE TABLE `t_user` (\n  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',\n  `name` varchar(30) NOT NULL DEFAULT '' COMMENT '姓名',\n  `age` int(11) NULL DEFAULT NULL COMMENT '年龄',\n  `gender` tinyint(2) NOT NULL DEFAULT 0 COMMENT '性别，0：女 1：男',\n  PRIMARY KEY (`id`)\n) COMMENT = '用户表';\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>再定义一个名为 \u003Ccode>User\u003C\u002Fcode> 实体类：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\n@Data\n@TableName(&quot;t_user&quot;)\npublic class User {\n    \u002F**\n     * 主键 ID, @TableId 注解定义字段为表的主键，type 表示主键类型，IdType.AUTO 表示随着数据库 ID 自增\n     *\u002F\n    @TableId(type = IdType.AUTO)\n    private Long id;\n    \u002F**\n     * 姓名\n     *\u002F\n    private String name;\n    \u002F**\n     * 年龄\n     *\u002F\n    private Integer age;\n    \u002F**\n     * 性别\n     *\u002F\n    private Integer gender;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cblockquote>\n\u003Cp>TIP： \u003Ccode>@Data\u003C\u002Fcode> 是 Lombok 注解，偷懒用的，加上它即可免写繁杂的 \u003Ccode>getXXX\u002FsetXXX\u003C\u002Fcode> 相关方法，不了解的小伙伴可自行搜索一下如何使用。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2>Mybatis Plus 伪批量插入\u003C\u002Fh2>\n\u003Cp>在前面《新增数据》\u003Cspan>\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" style=\"color: #aaa; margin-left: 3px;\" aria-hidden=\"true\" focusable=\"false\" x=\"0px\" y=\"0px\" viewBox=\"0 0 100 100\" width=\"15\" height=\"15\" class=\"icon outbound\">\u003Cpath fill=\"currentColor\" d=\"M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z\">\u003C\u002Fpath> \u003Cpolygon fill=\"currentColor\" points=\"45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9\">\u003C\u002Fpolygon>\u003C\u002Fsvg> \u003Cspan class=\"sr-only\">\u003C\u002Fspan>\u003C\u002Fspan>小节中，我们已经知道了 Mybatis Plus 内部封装的批量插入 \u003Ccode>savaBatch()\u003C\u002Fcode> 是个\u003Cstrong>假的批量插入\u003C\u002Fstrong>，示例代码如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>List&lt;User&gt; users = new ArrayList&lt;&gt;();\nfor (int i = 0; i &lt; 5; i++) {\n    User user = new User();\n    user.setName(&quot;张三&quot; + i);\n    user.setAge(i);\n    user.setGender(1);\n    users.add(user);\n}\n\u002F\u002F 批量插入\nboolean isSuccess = userService.saveBatch(users);\nSystem.out.println(&quot;isSuccess:&quot; + isSuccess);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>通过打印实际执行 SQL , 我们发现还是一条一条的执行 \u003Ccode>INSERT\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cp>\n\u003Cimg src=\"\u002Fupload\u002F167211863047181-DEdJ.jpg\" loading=\"lazy\">\n\u003C\u002Fp>\n\u003Cp>并且还带着大家看了内部实现的源码，这种方式比起自己 \u003Ccode>for\u003C\u002Fcode> 循环一条一条 \u003Ccode>INSERT\u003C\u002Fcode> 插入数据性能要更高，原因是在\u003Cstrong>会话这块做了优化\u003C\u002Fstrong>，虽然实际执行并不是真的批量插入。\u003C\u002Fp>\n\u003Ch2>利用 SQL 注入器实现真的批量插入\u003C\u002Fh2>\n\u003Cp>接下来，本文就手把手带你通过 Mybatis Plus 框架的 SQL 注入器实现一个真的批量插入。\u003C\u002Fp>\n\u003Ch3>示例项目结构\u003C\u002Fh3>\n\u003Cp>先贴一张示例项目的结构：\u003C\u002Fp>\n\u003Cp>\n\u003Cimg src=\"\u002Fupload\u002F167291645197992-KIGA.jpg\" loading=\"lazy\">\n\u003C\u002Fp>\n\u003Cp>注意看我红线标注的部分，主要关注这 4 个类与接口。\u003C\u002Fp>\n\u003Ch3>新建批量插入 SQL 注入器\u003C\u002Fh3>\n\u003Cp>在工程 \u003Ccode>config\u003C\u002Fcode> 目录下创建一个 SQL 注入器 \u003Ccode>InsertBatchSqlInjector\u003C\u002Fcode>  ：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * @author: 张三\n * @date: 2023-01-05 14:42\n * @version: v1.0.0\n * @description: 批量插入 SQL 注入器\n **\u002F\npublic class InsertBatchSqlInjector extends DefaultSqlInjector {\n\n    @Override\n    public List&lt;AbstractMethod&gt; getMethodList(Class&lt;?&gt; mapperClass, TableInfo tableInfo) {\n    \t\u002F\u002F super.getMethodList() 保留 Mybatis Plus 自带的方法\n        List&lt;AbstractMethod&gt; methodList = super.getMethodList(mapperClass, tableInfo);\n        \u002F\u002F 添加自定义方法：批量插入，方法名为 insertBatchSomeColumn\n        methodList.add(new InsertBatchSomeColumn());\n        return methodList;\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch4>说说 InsertBatchSomeColumn\u003C\u002Fh4>\n\u003Cp>\u003Ccode>InsertBatchSomeColumn\u003C\u002Fcode> 是 Mybatis Plus 内部提供的默认批量插入，只不过这个方法作者只在 MySQL 数据测试过，所以没有将它作为通用方法供外部调用，注意看注释：\u003C\u002Fp>\n\u003Cp>\n\u003Cimg src=\"\u002Fupload\u002F167291823412173-zlfC.jpg\" loading=\"lazy\">\n\u003C\u002Fp>\n\u003Cp>源码复制出来，如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * 批量新增数据,自选字段 insert\n * &lt;p&gt; 不同的数据库支持度不一样!!!  只在 mysql 下测试过!!!  只在 mysql 下测试过!!!  只在 mysql 下测试过!!! &lt;\u002Fp&gt;\n * &lt;p&gt; 除了主键是 &lt;strong&gt; 数据库自增的未测试 &lt;\u002Fstrong&gt; 外理论上都可以使用!!! &lt;\u002Fp&gt;\n * &lt;p&gt; 如果你使用自增有报错或主键值无法回写到entity,就不要跑来问为什么了,因为我也不知道!!! &lt;\u002Fp&gt;\n * &lt;p&gt;\n * 自己的通用 mapper 如下使用:\n * &lt;pre&gt;\n * int insertBatchSomeColumn(List&lt;T&gt; entityList);\n * &lt;\u002Fpre&gt;\n * &lt;\u002Fp&gt;\n *\n * &lt;li&gt; 注意: 这是自选字段 insert !!,如果个别字段在 entity 里为 null 但是数据库中有配置默认值, insert 后数据库字段是为 null 而不是默认值 &lt;\u002Fli&gt;\n *\n * &lt;p&gt;\n * 常用的 {@link Predicate}:\n * &lt;\u002Fp&gt;\n *\n * &lt;li&gt; 例1: t -&gt; !t.isLogicDelete() , 表示不要逻辑删除字段 &lt;\u002Fli&gt;\n * &lt;li&gt; 例2: t -&gt; !t.getProperty().equals(&quot;version&quot;) , 表示不要字段名为 version 的字段 &lt;\u002Fli&gt;\n * &lt;li&gt; 例3: t -&gt; t.getFieldFill() != FieldFill.UPDATE) , 表示不要填充策略为 UPDATE 的字段 &lt;\u002Fli&gt;\n *\n * @author miemie\n * @since 2018-11-29\n *\u002F\n\n@SuppressWarnings(&quot;serial&quot;)\npublic class InsertBatchSomeColumn extends AbstractMethod {\n\n    \u002F**\n     * 字段筛选条件\n     *\u002F\n    @Setter\n    @Accessors(chain = true)\n    private Predicate&lt;TableFieldInfo&gt; predicate;\n\n    \u002F**\n     * 默认方法名\n     *\u002F\n    public InsertBatchSomeColumn() {\n    \t\u002F\u002F 方法名\n        super(&quot;insertBatchSomeColumn&quot;);\n    }\n\n    \u002F**\n     * 默认方法名\n     *\n     * @param predicate 字段筛选条件\n     *\u002F\n    public InsertBatchSomeColumn(Predicate&lt;TableFieldInfo&gt; predicate) {\n        super(&quot;insertBatchSomeColumn&quot;);\n        this.predicate = predicate;\n    }\n\n    \u002F**\n     * @param name      方法名\n     * @param predicate 字段筛选条件\n     * @since 3.5.0\n     *\u002F\n    public InsertBatchSomeColumn(String name, Predicate&lt;TableFieldInfo&gt; predicate) {\n        super(name);\n        this.predicate = predicate;\n    }\n\n    @SuppressWarnings(&quot;Duplicates&quot;)\n    @Override\n    public MappedStatement injectMappedStatement(Class&lt;?&gt; mapperClass, Class&lt;?&gt; modelClass, TableInfo tableInfo) {\n        KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;\n        SqlMethod sqlMethod = SqlMethod.INSERT_ONE;\n        List&lt;TableFieldInfo&gt; fieldList = tableInfo.getFieldList();\n        String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(true, false) +\n            this.filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY);\n        String columnScript = LEFT_BRACKET + insertSqlColumn.substring(0, insertSqlColumn.length() - 1) + RIGHT_BRACKET;\n        String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(true, ENTITY_DOT, false) +\n            this.filterTableFieldInfo(fieldList, predicate, i -&gt; i.getInsertSqlProperty(ENTITY_DOT), EMPTY);\n        insertSqlProperty = LEFT_BRACKET + insertSqlProperty.substring(0, insertSqlProperty.length() - 1) + RIGHT_BRACKET;\n        String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, &quot;list&quot;, null, ENTITY, COMMA);\n        String keyProperty = null;\n        String keyColumn = null;\n        \u002F\u002F 表包含主键处理逻辑,如果不包含主键当普通字段处理\n        if (tableInfo.havePK()) {\n            if (tableInfo.getIdType() == IdType.AUTO) {\n                \u002F* 自增主键 *\u002F\n                keyGenerator = Jdbc3KeyGenerator.INSTANCE;\n                keyProperty = tableInfo.getKeyProperty();\n                keyColumn = tableInfo.getKeyColumn();\n            } else {\n                if (null != tableInfo.getKeySequence()) {\n                    keyGenerator = TableInfoHelper.genKeyGenerator(this.methodName, tableInfo, builderAssistant);\n                    keyProperty = tableInfo.getKeyProperty();\n                    keyColumn = tableInfo.getKeyColumn();\n                }\n            }\n        }\n        String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript);\n        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);\n        return this.addInsertMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource, keyGenerator, keyProperty, keyColumn);\n    }\n\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>配置 SQL 注入器\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>config\u003C\u002Fcode> 包下创建 \u003Ccode>MybatisPlusConfig\u003C\u002Fcode> 配置类：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * @Author: 张三\n * @Date: 2022-12-15 18:29\n * @Version: v1.0.0\n * @Description: TODO\n **\u002F\n@Configuration\n@MapperScan(&quot;com.mashangan.mybatisplusdemo.mapper&quot;)\npublic class MybatisPlusConfig {\n\n\n    \u002F**\n     * 自定义批量插入 SQL 注入器\n     *\u002F\n    @Bean\n    public InsertBatchSqlInjector insertBatchSqlInjector() {\n        return new InsertBatchSqlInjector();\n    }\n\n}\n\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>新建 MyBaseMapper\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>config\u003C\u002Fcode> 包下创建 \u003Ccode>MyBaseMapper\u003C\u002Fcode> 接口，让其继承自 Mybatis Plus 提供的 \u003Ccode>BaseMapper\u003C\u002Fcode>, 并定义批量插入方法：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\npublic interface MyBaseMapper&lt;T&gt; extends BaseMapper&lt;T&gt; {\n\n\t\u002F\u002F 批量插入\n    int insertBatchSomeColumn(@Param(&quot;list&quot;) List&lt;T&gt; batchList);\n\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cblockquote>\n\u003Cp>注意：方法名必须为 \u003Ccode>insertBatchSomeColumn\u003C\u002Fcode>, 和 \u003Ccode>InsertBatchSomeColumn\u003C\u002Fcode> 内部定义好的方法名保持一致。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch3>新建 UserMapper\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>mapper\u003C\u002Fcode> 包下创建 \u003Ccode>UserMapper\u003C\u002Fcode> 接口，注意继承刚刚自定义的 \u003Ccode>MyBaseMapper\u003C\u002Fcode>, 而不是 \u003Ccode>BaseMapper\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\npublic interface UserMapper extends MyBaseMapper&lt;User&gt; {\n}\n\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>测试批量插入\u003C\u002Fh2>\n\u003Cp>完成上面这些工作后，就可以使用 Mybatis Plus 提供的批量插入功能了。我们新建一个单元测试，并注入 \u003Ccode>UserMapper\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode>@Autowired\nprivate UserMapper userMapper;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>单元测试如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>@Test\nvoid testInsertBatch() {\n    List&lt;User&gt; users = new ArrayList&lt;&gt;();\n    for (int i = 0; i &lt; 3; i++) {\n        User user = new User();\n        user.setName(&quot;张三&quot; + i);\n        user.setAge(i);\n        user.setGender(1);\n        users.add(user);\n    }\n\n    userMapper.insertBatchSomeColumn(users);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>控制台实际执行 SQL 如下：\u003C\u002Fp>\n\u003Cp>\n\u003Cimg src=\"\u002Fupload\u002F167292369282647-hkCh.jpg\" loading=\"lazy\">\n\u003C\u002Fp>\n\u003Cp>可以看到这次是真实的批量插入了，舒服了~\u003C\u002Fp>\n\u003Ch2>性能对比\u003C\u002Fh2>\n\u003Cp>我们来测试一下插入 105000  条数据，分别使用 \u003Ccode>for\u003C\u002Fcode> 循环插入数据、\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入、与真实批量插入三种模式，看看耗时差距多少。\u003C\u002Fp>\n\u003Cp>这里的机器配置如下：\u003C\u002Fp>\n\u003Cp>\n\u003Cimg src=\"\u002Fupload\u002F167292550362580-Ukgp.jpg\" loading=\"lazy\">\n\u003C\u002Fp>\n\u003Ch3>\u003Ccode>for\u003C\u002Fcode> 循环插入\u003C\u002Fh3>\n\u003Cp>单元测试代码如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>@Test\nvoid testInsert1() {\n    \u002F\u002F 总耗时：722963 ms, 约 12 分钟\n    long start = System.currentTimeMillis();\n    for (int i = 0; i &lt; 105000; i++) {\n        User user = new User();\n        user.setName(&quot;张三&quot; + i);\n        user.setAge(i);\n        user.setGender(1);\n        userMapper.insert(user);\n    }\n    System.out.println(String.format(&quot;总耗时：%s ms&quot;, System.currentTimeMillis() - start));\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入\u003C\u002Fh3>\n\u003Cp>单元测试代码如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>@Test\nvoid testInsert2() {\n    \u002F\u002F 总耗时：95864 ms, 约一分钟30秒左右\n    long start = System.currentTimeMillis();\n    List&lt;User&gt; users = new ArrayList&lt;&gt;();\n    for (int i = 0; i &lt; 105000; i++) {\n        User user = new User();\n        user.setName(&quot;张三&quot; + i);\n        user.setAge(i);\n        user.setGender(1);\n        users.add(user);\n    }\n    userService.saveBatch(users);\n    System.out.println(String.format(&quot;总耗时：%s ms&quot;, System.currentTimeMillis() - start));\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>真实批量插入\u003C\u002Fh3>\n\u003Cp>注意，\u003Cstrong>真实业务场景下，也不可能会将 10 万多条记录组装成一条 SQL 进行批量插入\u003C\u002Fstrong>，因为数据库对执行 SQL 大小是有限制的（这个数值可以自行设置），还是需要分片插入，比如取 1000 条执行一次批量插入，单元测试代码如下：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>@Test\n    void testInsertBatch1() {\n        \u002F\u002F 总耗时：6320 ms, 约 6 秒\n        long start = System.currentTimeMillis();\n        List&lt;User&gt; users = new ArrayList&lt;&gt;();\n        for (int i = 0; i &lt; 105000; i++) {\n            User user = new User();\n            user.setName(&quot;张三&quot; + i);\n            user.setAge(i);\n            user.setGender(1);\n            users.add(user);\n        }\n\n        \u002F\u002F 分片插入（每 1000 条执行一次批量插入）\n        int batchSize = 1000;\n        int total = users.size();\n        \u002F\u002F 需要执行的次数\n        int insertTimes = total \u002F batchSize;\n        \u002F\u002F 最后一次执行需要提交的记录数（防止可能不足 1000 条）\n        int lastSize = batchSize;\n        if (total % batchSize != 0) {\n            insertTimes++;\n            lastSize = total%batchSize;\n        }\n\n        for (int j = 0; j &lt; insertTimes; j++) {\n            if (insertTimes == j+1) {\n                batchSize = lastSize;\n            }\n\n            \u002F\u002F 分片执行批量插入\n            userMapper.insertBatchSomeColumn(users.subList(j*batchSize, (j*batchSize+batchSize)));\n        }\n        System.out.println(String.format(&quot;总耗时：%s ms&quot;, System.currentTimeMillis() - start));\n    }\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>耗时对比\u003C\u002Fh3>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>方式\u003C\u002Fth>\n\u003Cth>总耗时\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>for\u003C\u002Fcode> 循环插入\u003C\u002Ftd>\n\u003Ctd>722963 ms, 约 12 分钟\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入\u003C\u002Ftd>\n\u003Ctd>95864 ms, 约一分钟30秒左右\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>真实批量插入\u003C\u002Ftd>\n\u003Ctd>6320 ms, 约 6 秒\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>耗时对比非常直观，在大批量数据新增的场景下，批量插入性能最高。\u003C\u002Fp>\n\u003Ch2>结语\u003C\u002Fh2>\n\u003Cp>本小节中，我们学习了如何通过 Mybatis Plus 的 SQL 注入器实现真实的批量插入，同时最后还对比了三种不同方式插入 10 万多数据的耗时，很直观的看到在海量数据场景下，批量插入的性能是最强的。\u003C\u002Fp>\n13:T13be6,\u003Ch2 id=\"toc-0\">前言\u003C\u002Fh2>\n\u003Cp>大家好。\u003C\u002Fp>\n\u003Cp>本小节中，我们将学习如何通过 Mybatis Plus 实现 MySQL 批量插入数据。\u003C\u002Fp>\n\u003Ch2 id=\"toc-1\">什么是批量插入？优势在哪里？\u003C\u002Fh2>\n\u003Cp>\u003Cem>先抛出一个问题：假设老板给你下了个任务，向数据库中添加 100 万条数据，并且不能耗时太久！\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>通常来说，我们向 MySQL 中新增一条记录，SQL 语句类似如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-javascript\" data-ext=\"javascript\" data-code=\"INSERT%20INTO%20%60t_user%60%20(%60name%60%2C%20%60age%60%2C%20%60gender%60)%20VALUES%20('%E5%BC%A0%E4%B8%890'%2C%200%2C%201)%3B%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-javascript\">\u003Cspan class=\"token constant\">INSERT\u003C\u002Fspan> \u003Cspan class=\"token constant\">INTO\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">t_user\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">name\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">age\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">gender\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token constant\">VALUES\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">'张三0'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>如果你需要添加 100 万条数据，就需要多次执行此语句，这就意味着频繁地 IO 操作（网络 IO、磁盘 IO），并且每一次数据库执行 SQL 都需要进行解析、优化等操作，都会导致非常耗时。\u003C\u002Fp>\n\u003Cp>幸运的是，MySQL 支持一条 SQL 语句可以批量插入多条记录，格式如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-javascript\" data-ext=\"javascript\" data-code=\"INSERT%20INTO%20%60t_user%60%20(%60name%60%2C%20%60age%60%2C%20%60gender%60)%20VALUES%20('%E5%BC%A0%E4%B8%890'%2C%200%2C%201)%2C%20('%E5%BC%A0%E4%B8%891'%2C%200%2C%201)%2C%20('%E5%BC%A0%E4%B8%893'%2C%200%2C%201)%3B%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-javascript\">\u003Cspan class=\"token constant\">INSERT\u003C\u002Fspan> \u003Cspan class=\"token constant\">INTO\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">t_user\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">name\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">age\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token template-string\">\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003Cspan class=\"token string\">gender\u003C\u002Fspan>\u003Cspan class=\"token template-punctuation string\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token constant\">VALUES\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">'张三0'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">'张三1'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">'张三3'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>和常规的 \u003Ccode>INSERT\u003C\u002Fcode> 语句不同的是，\u003Ccode>VALUES\u003C\u002Fcode> 支持多条记录，通过 \u003Ccode>,\u003C\u002Fcode> 逗号隔开。这样，可以实现一次性插入多条记录。\u003C\u002Fp>\n\u003Cp>数据量不多的情况下，常规 \u003Ccode>INSERT\u003C\u002Fcode> 和批量插入性能差距不大，但是，一旦数量级上去后，执行耗时差距就拉开了，在后面我们会实测一下它们之间的耗时对比。\u003C\u002Fp>\n\u003Ch2 id=\"toc-2\">表与实体类\u003C\u002Fh2>\n\u003Cp>先创建一个测试表 \u003Ccode>t_user\u003C\u002Fcode>, 执行脚本如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-sql\" data-ext=\"sql\" data-code=\"DROP%20TABLE%20IF%20EXISTS%20user%3B%0A%0ACREATE%20TABLE%20%60t_user%60%20(%0A%20%20%60id%60%20bigint(20)%20UNSIGNED%20NOT%20NULL%20AUTO_INCREMENT%20COMMENT%20'%E4%B8%BB%E9%94%AEID'%2C%0A%20%20%60name%60%20varchar(30)%20NOT%20NULL%20DEFAULT%20''%20COMMENT%20'%E5%A7%93%E5%90%8D'%2C%0A%20%20%60age%60%20int(11)%20NULL%20DEFAULT%20NULL%20COMMENT%20'%E5%B9%B4%E9%BE%84'%2C%0A%20%20%60gender%60%20tinyint(2)%20NOT%20NULL%20DEFAULT%200%20COMMENT%20'%E6%80%A7%E5%88%AB%EF%BC%8C0%EF%BC%9A%E5%A5%B3%201%EF%BC%9A%E7%94%B7'%2C%0A%20%20PRIMARY%20KEY%20(%60id%60)%0A)%20COMMENT%20%3D%20'%E7%94%A8%E6%88%B7%E8%A1%A8'%3B%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-sql\">\u003Cspan class=\"token keyword\">DROP\u003C\u002Fspan> \u003Cspan class=\"token keyword\">TABLE\u003C\u002Fspan> \u003Cspan class=\"token keyword\">IF\u003C\u002Fspan> \u003Cspan class=\"token keyword\">EXISTS\u003C\u002Fspan> \u003Cspan class=\"token keyword\">user\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\n\u003Cspan class=\"token keyword\">CREATE\u003C\u002Fspan> \u003Cspan class=\"token keyword\">TABLE\u003C\u002Fspan> \u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>t_user\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\n  \u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>id\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token keyword\">bigint\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">20\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token keyword\">UNSIGNED\u003C\u002Fspan> \u003Cspan class=\"token operator\">NOT\u003C\u002Fspan> \u003Cspan class=\"token boolean\">NULL\u003C\u002Fspan> \u003Cspan class=\"token keyword\">AUTO_INCREMENT\u003C\u002Fspan> \u003Cspan class=\"token keyword\">COMMENT\u003C\u002Fspan> \u003Cspan class=\"token string\">'主键ID'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan>\n  \u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>name\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token keyword\">varchar\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">30\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">NOT\u003C\u002Fspan> \u003Cspan class=\"token boolean\">NULL\u003C\u002Fspan> \u003Cspan class=\"token keyword\">DEFAULT\u003C\u002Fspan> \u003Cspan class=\"token string\">''\u003C\u002Fspan> \u003Cspan class=\"token keyword\">COMMENT\u003C\u002Fspan> \u003Cspan class=\"token string\">'姓名'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan>\n  \u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>age\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token keyword\">int\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">11\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token boolean\">NULL\u003C\u002Fspan> \u003Cspan class=\"token keyword\">DEFAULT\u003C\u002Fspan> \u003Cspan class=\"token boolean\">NULL\u003C\u002Fspan> \u003Cspan class=\"token keyword\">COMMENT\u003C\u002Fspan> \u003Cspan class=\"token string\">'年龄'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan>\n  \u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>gender\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token keyword\">tinyint\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">2\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">NOT\u003C\u002Fspan> \u003Cspan class=\"token boolean\">NULL\u003C\u002Fspan> \u003Cspan class=\"token keyword\">DEFAULT\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan> \u003Cspan class=\"token keyword\">COMMENT\u003C\u002Fspan> \u003Cspan class=\"token string\">'性别，0：女 1：男'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan>\n  \u003Cspan class=\"token keyword\">PRIMARY\u003C\u002Fspan> \u003Cspan class=\"token keyword\">KEY\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token identifier\">\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>id\u003Cspan class=\"token punctuation\">`\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token keyword\">COMMENT\u003C\u002Fspan> \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token string\">'用户表'\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>再定义一个名为 \u003Ccode>User\u003C\u002Fcode> 实体类：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%40author%3A%20%E5%BC%A0%E4%B8%89%0A%20*%20%40from%3A%20%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%9A%E5%BC%A0%E4%B8%89%2C%20%E7%BD%91%E7%AB%99%EF%BC%9Awww.mashangan.com%0A%20*%20%40date%3A%202022-12-13%2014%3A13%0A%20*%20%40version%3A%20v1.0.0%0A%20*%20%40description%3A%20TODO%0A%20**%2F%0A%40Data%0A%40TableName(%22t_user%22)%0Apublic%20class%20User%20%7B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E4%B8%BB%E9%94%AE%20ID%2C%20%40TableId%20%E6%B3%A8%E8%A7%A3%E5%AE%9A%E4%B9%89%E5%AD%97%E6%AE%B5%E4%B8%BA%E8%A1%A8%E7%9A%84%E4%B8%BB%E9%94%AE%EF%BC%8Ctype%20%E8%A1%A8%E7%A4%BA%E4%B8%BB%E9%94%AE%E7%B1%BB%E5%9E%8B%EF%BC%8CIdType.AUTO%20%E8%A1%A8%E7%A4%BA%E9%9A%8F%E7%9D%80%E6%95%B0%E6%8D%AE%E5%BA%93%20ID%20%E8%87%AA%E5%A2%9E%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40TableId(type%20%3D%20IdType.AUTO)%0A%20%20%20%20private%20Long%20id%3B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%A7%93%E5%90%8D%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20String%20name%3B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%B9%B4%E9%BE%84%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20Integer%20age%3B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%80%A7%E5%88%AB%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20Integer%20gender%3B%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\u003C\u002Fspan>\n\u003Cspan class=\"token annotation punctuation\">@Data\u003C\u002Fspan>\n\u003Cspan class=\"token annotation punctuation\">@TableName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"t_user\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">class\u003C\u002Fspan> \u003Cspan class=\"token class-name\">User\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F**\n     * 主键 ID, @TableId 注解定义字段为表的主键，type 表示主键类型，IdType.AUTO 表示随着数据库 ID 自增\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token annotation punctuation\">@TableId\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>type \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">IdType\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token constant\">AUTO\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Long\u003C\u002Fspan> id\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F**\n     * 姓名\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> name\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F**\n     * 年龄\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Integer\u003C\u002Fspan> age\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F**\n     * 性别\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Integer\u003C\u002Fspan> gender\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cblockquote>\n\u003Cp>TIP： \u003Ccode>@Data\u003C\u002Fcode> 是 Lombok 注解，偷懒用的，加上它即可免写繁杂的 \u003Ccode>getXXX\u002FsetXXX\u003C\u002Fcode> 相关方法，不了解的小伙伴可自行搜索一下如何使用。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2 id=\"toc-3\">Mybatis Plus 伪批量插入\u003C\u002Fh2>\n\u003Cp>在前面《新增数据》\u003Cspan>\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" style=\"color: #aaa; margin-left: 3px;\" aria-hidden=\"true\" focusable=\"false\" x=\"0px\" y=\"0px\" viewBox=\"0 0 100 100\" width=\"15\" height=\"15\" class=\"icon outbound\">\u003Cpath fill=\"currentColor\" d=\"M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z\">\u003C\u002Fpath> \u003Cpolygon fill=\"currentColor\" points=\"45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9\">\u003C\u002Fpolygon>\u003C\u002Fsvg> \u003Cspan class=\"sr-only\">\u003C\u002Fspan>\u003C\u002Fspan>小节中，我们已经知道了 Mybatis Plus 内部封装的批量插入 \u003Ccode>savaBatch()\u003C\u002Fcode> 是个\u003Cstrong>假的批量插入\u003C\u002Fstrong>，示例代码如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-dockerfile\" data-ext=\"dockerfile\" data-code=\"List%3CUser%3E%20users%20%3D%20new%20ArrayList%3C%3E()%3B%0Afor%20(int%20i%20%3D%200%3B%20i%20%3C%205%3B%20i%2B%2B)%20%7B%0A%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20user.setName(%22%E5%BC%A0%E4%B8%89%22%20%2B%20i)%3B%0A%20%20%20%20user.setAge(i)%3B%0A%20%20%20%20user.setGender(1)%3B%0A%20%20%20%20users.add(user)%3B%0A%7D%0A%2F%2F%20%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%0Aboolean%20isSuccess%20%3D%20userService.saveBatch(users)%3B%0ASystem.out.println(%22isSuccess%3A%22%20%2B%20isSuccess)%3B%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-dockerfile\">List&lt;User> users = new ArrayList&lt;>();\nfor (int i = 0; i &lt; 5; i++) {\n    \u003Cspan class=\"token instruction\">\u003Cspan class=\"token keyword\">User\u003C\u002Fspan> user = new User();\u003C\u002Fspan>\n    user.setName(\"张三\" + i);\n    user.setAge(i);\n    user.setGender(1);\n    users.add(user);\n}\n\u002F\u002F 批量插入\nboolean isSuccess = userService.saveBatch(users);\nSystem.out.println(\"isSuccess:\" + isSuccess);\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>通过打印实际执行 SQL , 我们发现还是一条一条的执行 \u003Ccode>INSERT\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cp>\n\u003Cdiv class=\"img-loading\">\u003Cimg src=\"\u002Fupload\u002F167211863047181-DEdJ.jpg\" loading=\"lazy\">\u003C\u002Fdiv>\n\u003C\u002Fp>\n\u003Cp>并且还带着大家看了内部实现的源码，这种方式比起自己 \u003Ccode>for\u003C\u002Fcode> 循环一条一条 \u003Ccode>INSERT\u003C\u002Fcode> 插入数据性能要更高，原因是在\u003Cstrong>会话这块做了优化\u003C\u002Fstrong>，虽然实际执行并不是真的批量插入。\u003C\u002Fp>\n\u003Ch2 id=\"toc-4\">利用 SQL 注入器实现真的批量插入\u003C\u002Fh2>\n\u003Cp>接下来，本文就手把手带你通过 Mybatis Plus 框架的 SQL 注入器实现一个真的批量插入。\u003C\u002Fp>\n\u003Ch3 id=\"toc-5\">示例项目结构\u003C\u002Fh3>\n\u003Cp>先贴一张示例项目的结构：\u003C\u002Fp>\n\u003Cp>\n\u003Cdiv class=\"img-loading\">\u003Cimg src=\"\u002Fupload\u002F167291645197992-KIGA.jpg\" loading=\"lazy\">\u003C\u002Fdiv>\n\u003C\u002Fp>\n\u003Cp>注意看我红线标注的部分，主要关注这 4 个类与接口。\u003C\u002Fp>\n\u003Ch3 id=\"toc-6\">新建批量插入 SQL 注入器\u003C\u002Fh3>\n\u003Cp>在工程 \u003Ccode>config\u003C\u002Fcode> 目录下创建一个 SQL 注入器 \u003Ccode>InsertBatchSqlInjector\u003C\u002Fcode>  ：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%40author%3A%20%E5%BC%A0%E4%B8%89%0A%20*%20%40from%3A%20%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%9A%E5%BC%A0%E4%B8%89%2C%20%E7%BD%91%E7%AB%99%EF%BC%9Awww.mashangan.com%0A%20*%20%40date%3A%202023-01-05%2014%3A42%0A%20*%20%40version%3A%20v1.0.0%0A%20*%20%40description%3A%20%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%20SQL%20%E6%B3%A8%E5%85%A5%E5%99%A8%0A%20**%2F%0Apublic%20class%20InsertBatchSqlInjector%20extends%20DefaultSqlInjector%20%7B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20List%3CAbstractMethod%3E%20getMethodList(Class%3C%3F%3E%20mapperClass%2C%20TableInfo%20tableInfo)%20%7B%0A%20%20%20%20%09%2F%2F%20super.getMethodList()%20%E4%BF%9D%E7%95%99%20Mybatis%20Plus%20%E8%87%AA%E5%B8%A6%E7%9A%84%E6%96%B9%E6%B3%95%0A%20%20%20%20%20%20%20%20List%3CAbstractMethod%3E%20methodList%20%3D%20super.getMethodList(mapperClass%2C%20tableInfo)%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E6%B7%BB%E5%8A%A0%E8%87%AA%E5%AE%9A%E4%B9%89%E6%96%B9%E6%B3%95%EF%BC%9A%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%EF%BC%8C%E6%96%B9%E6%B3%95%E5%90%8D%E4%B8%BA%20insertBatchSomeColumn%0A%20%20%20%20%20%20%20%20methodList.add(new%20InsertBatchSomeColumn())%3B%0A%20%20%20%20%20%20%20%20return%20methodList%3B%0A%20%20%20%20%7D%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * @author: 张三\n * @date: 2023-01-05 14:42\n * @version: v1.0.0\n * @description: 批量插入 SQL 注入器\n **\u002F\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">class\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSqlInjector\u003C\u002Fspan> \u003Cspan class=\"token keyword\">extends\u003C\u002Fspan> \u003Cspan class=\"token class-name\">DefaultSqlInjector\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n\n    \u003Cspan class=\"token annotation punctuation\">@Override\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">AbstractMethod\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token function\">getMethodList\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">Class\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token operator\">?\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> mapperClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">TableInfo\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \t\u003Cspan class=\"token comment\">\u002F\u002F super.getMethodList() 保留 Mybatis Plus 自带的方法\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">AbstractMethod\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> methodList \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">super\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getMethodList\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>mapperClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token comment\">\u002F\u002F 添加自定义方法：批量插入，方法名为 insertBatchSomeColumn\u003C\u002Fspan>\n        methodList\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">add\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">return\u003C\u002Fspan> methodList\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch4 id=\"toc-7\">说说 InsertBatchSomeColumn\u003C\u002Fh4>\n\u003Cp>\u003Ccode>InsertBatchSomeColumn\u003C\u002Fcode> 是 Mybatis Plus 内部提供的默认批量插入，只不过这个方法作者只在 MySQL 数据测试过，所以没有将它作为通用方法供外部调用，注意看注释：\u003C\u002Fp>\n\u003Cp>\n\u003Cdiv class=\"img-loading\">\u003Cimg src=\"\u002Fupload\u002F167291823412173-zlfC.jpg\" loading=\"lazy\">\u003C\u002Fdiv>\n\u003C\u002Fp>\n\u003Cp>源码复制出来，如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%E6%89%B9%E9%87%8F%E6%96%B0%E5%A2%9E%E6%95%B0%E6%8D%AE%2C%E8%87%AA%E9%80%89%E5%AD%97%E6%AE%B5%20insert%0A%20*%20%3Cp%3E%20%E4%B8%8D%E5%90%8C%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E6%94%AF%E6%8C%81%E5%BA%A6%E4%B8%8D%E4%B8%80%E6%A0%B7!!!%20%20%E5%8F%AA%E5%9C%A8%20mysql%20%E4%B8%8B%E6%B5%8B%E8%AF%95%E8%BF%87!!!%20%20%E5%8F%AA%E5%9C%A8%20mysql%20%E4%B8%8B%E6%B5%8B%E8%AF%95%E8%BF%87!!!%20%20%E5%8F%AA%E5%9C%A8%20mysql%20%E4%B8%8B%E6%B5%8B%E8%AF%95%E8%BF%87!!!%20%3C%2Fp%3E%0A%20*%20%3Cp%3E%20%E9%99%A4%E4%BA%86%E4%B8%BB%E9%94%AE%E6%98%AF%20%3Cstrong%3E%20%E6%95%B0%E6%8D%AE%E5%BA%93%E8%87%AA%E5%A2%9E%E7%9A%84%E6%9C%AA%E6%B5%8B%E8%AF%95%20%3C%2Fstrong%3E%20%E5%A4%96%E7%90%86%E8%AE%BA%E4%B8%8A%E9%83%BD%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8!!!%20%3C%2Fp%3E%0A%20*%20%3Cp%3E%20%E5%A6%82%E6%9E%9C%E4%BD%A0%E4%BD%BF%E7%94%A8%E8%87%AA%E5%A2%9E%E6%9C%89%E6%8A%A5%E9%94%99%E6%88%96%E4%B8%BB%E9%94%AE%E5%80%BC%E6%97%A0%E6%B3%95%E5%9B%9E%E5%86%99%E5%88%B0entity%2C%E5%B0%B1%E4%B8%8D%E8%A6%81%E8%B7%91%E6%9D%A5%E9%97%AE%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BA%86%2C%E5%9B%A0%E4%B8%BA%E6%88%91%E4%B9%9F%E4%B8%8D%E7%9F%A5%E9%81%93!!!%20%3C%2Fp%3E%0A%20*%20%3Cp%3E%0A%20*%20%E8%87%AA%E5%B7%B1%E7%9A%84%E9%80%9A%E7%94%A8%20mapper%20%E5%A6%82%E4%B8%8B%E4%BD%BF%E7%94%A8%3A%0A%20*%20%3Cpre%3E%0A%20*%20int%20insertBatchSomeColumn(List%3CT%3E%20entityList)%3B%0A%20*%20%3C%2Fpre%3E%0A%20*%20%3C%2Fp%3E%0A%20*%0A%20*%20%3Cli%3E%20%E6%B3%A8%E6%84%8F%3A%20%E8%BF%99%E6%98%AF%E8%87%AA%E9%80%89%E5%AD%97%E6%AE%B5%20insert%20!!%2C%E5%A6%82%E6%9E%9C%E4%B8%AA%E5%88%AB%E5%AD%97%E6%AE%B5%E5%9C%A8%20entity%20%E9%87%8C%E4%B8%BA%20null%20%E4%BD%86%E6%98%AF%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E6%9C%89%E9%85%8D%E7%BD%AE%E9%BB%98%E8%AE%A4%E5%80%BC%2C%20insert%20%E5%90%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AD%97%E6%AE%B5%E6%98%AF%E4%B8%BA%20null%20%E8%80%8C%E4%B8%8D%E6%98%AF%E9%BB%98%E8%AE%A4%E5%80%BC%20%3C%2Fli%3E%0A%20*%0A%20*%20%3Cp%3E%0A%20*%20%E5%B8%B8%E7%94%A8%E7%9A%84%20%7B%40link%20Predicate%7D%3A%0A%20*%20%3C%2Fp%3E%0A%20*%0A%20*%20%3Cli%3E%20%E4%BE%8B1%3A%20t%20-%3E%20!t.isLogicDelete()%20%2C%20%E8%A1%A8%E7%A4%BA%E4%B8%8D%E8%A6%81%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4%E5%AD%97%E6%AE%B5%20%3C%2Fli%3E%0A%20*%20%3Cli%3E%20%E4%BE%8B2%3A%20t%20-%3E%20!t.getProperty().equals(%22version%22)%20%2C%20%E8%A1%A8%E7%A4%BA%E4%B8%8D%E8%A6%81%E5%AD%97%E6%AE%B5%E5%90%8D%E4%B8%BA%20version%20%E7%9A%84%E5%AD%97%E6%AE%B5%20%3C%2Fli%3E%0A%20*%20%3Cli%3E%20%E4%BE%8B3%3A%20t%20-%3E%20t.getFieldFill()%20!%3D%20FieldFill.UPDATE)%20%2C%20%E8%A1%A8%E7%A4%BA%E4%B8%8D%E8%A6%81%E5%A1%AB%E5%85%85%E7%AD%96%E7%95%A5%E4%B8%BA%20UPDATE%20%E7%9A%84%E5%AD%97%E6%AE%B5%20%3C%2Fli%3E%0A%20*%0A%20*%20%40author%20miemie%0A%20*%20%40since%202018-11-29%0A%20*%2F%0A%0A%40SuppressWarnings(%22serial%22)%0Apublic%20class%20InsertBatchSomeColumn%20extends%20AbstractMethod%20%7B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%AD%97%E6%AE%B5%E7%AD%9B%E9%80%89%E6%9D%A1%E4%BB%B6%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Setter%0A%20%20%20%20%40Accessors(chain%20%3D%20true)%0A%20%20%20%20private%20Predicate%3CTableFieldInfo%3E%20predicate%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%BB%98%E8%AE%A4%E6%96%B9%E6%B3%95%E5%90%8D%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20InsertBatchSomeColumn()%20%7B%0A%20%20%20%20%09%2F%2F%20%E6%96%B9%E6%B3%95%E5%90%8D%0A%20%20%20%20%20%20%20%20super(%22insertBatchSomeColumn%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%BB%98%E8%AE%A4%E6%96%B9%E6%B3%95%E5%90%8D%0A%20%20%20%20%20*%0A%20%20%20%20%20*%20%40param%20predicate%20%E5%AD%97%E6%AE%B5%E7%AD%9B%E9%80%89%E6%9D%A1%E4%BB%B6%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20InsertBatchSomeColumn(Predicate%3CTableFieldInfo%3E%20predicate)%20%7B%0A%20%20%20%20%20%20%20%20super(%22insertBatchSomeColumn%22)%3B%0A%20%20%20%20%20%20%20%20this.predicate%20%3D%20predicate%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%40param%20name%20%20%20%20%20%20%E6%96%B9%E6%B3%95%E5%90%8D%0A%20%20%20%20%20*%20%40param%20predicate%20%E5%AD%97%E6%AE%B5%E7%AD%9B%E9%80%89%E6%9D%A1%E4%BB%B6%0A%20%20%20%20%20*%20%40since%203.5.0%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20InsertBatchSomeColumn(String%20name%2C%20Predicate%3CTableFieldInfo%3E%20predicate)%20%7B%0A%20%20%20%20%20%20%20%20super(name)%3B%0A%20%20%20%20%20%20%20%20this.predicate%20%3D%20predicate%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40SuppressWarnings(%22Duplicates%22)%0A%20%20%20%20%40Override%0A%20%20%20%20public%20MappedStatement%20injectMappedStatement(Class%3C%3F%3E%20mapperClass%2C%20Class%3C%3F%3E%20modelClass%2C%20TableInfo%20tableInfo)%20%7B%0A%20%20%20%20%20%20%20%20KeyGenerator%20keyGenerator%20%3D%20NoKeyGenerator.INSTANCE%3B%0A%20%20%20%20%20%20%20%20SqlMethod%20sqlMethod%20%3D%20SqlMethod.INSERT_ONE%3B%0A%20%20%20%20%20%20%20%20List%3CTableFieldInfo%3E%20fieldList%20%3D%20tableInfo.getFieldList()%3B%0A%20%20%20%20%20%20%20%20String%20insertSqlColumn%20%3D%20tableInfo.getKeyInsertSqlColumn(true%2C%20false)%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20this.filterTableFieldInfo(fieldList%2C%20predicate%2C%20TableFieldInfo%3A%3AgetInsertSqlColumn%2C%20EMPTY)%3B%0A%20%20%20%20%20%20%20%20String%20columnScript%20%3D%20LEFT_BRACKET%20%2B%20insertSqlColumn.substring(0%2C%20insertSqlColumn.length()%20-%201)%20%2B%20RIGHT_BRACKET%3B%0A%20%20%20%20%20%20%20%20String%20insertSqlProperty%20%3D%20tableInfo.getKeyInsertSqlProperty(true%2C%20ENTITY_DOT%2C%20false)%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20this.filterTableFieldInfo(fieldList%2C%20predicate%2C%20i%20-%3E%20i.getInsertSqlProperty(ENTITY_DOT)%2C%20EMPTY)%3B%0A%20%20%20%20%20%20%20%20insertSqlProperty%20%3D%20LEFT_BRACKET%20%2B%20insertSqlProperty.substring(0%2C%20insertSqlProperty.length()%20-%201)%20%2B%20RIGHT_BRACKET%3B%0A%20%20%20%20%20%20%20%20String%20valuesScript%20%3D%20SqlScriptUtils.convertForeach(insertSqlProperty%2C%20%22list%22%2C%20null%2C%20ENTITY%2C%20COMMA)%3B%0A%20%20%20%20%20%20%20%20String%20keyProperty%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20String%20keyColumn%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E8%A1%A8%E5%8C%85%E5%90%AB%E4%B8%BB%E9%94%AE%E5%A4%84%E7%90%86%E9%80%BB%E8%BE%91%2C%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%8C%85%E5%90%AB%E4%B8%BB%E9%94%AE%E5%BD%93%E6%99%AE%E9%80%9A%E5%AD%97%E6%AE%B5%E5%A4%84%E7%90%86%0A%20%20%20%20%20%20%20%20if%20(tableInfo.havePK())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(tableInfo.getIdType()%20%3D%3D%20IdType.AUTO)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F*%20%E8%87%AA%E5%A2%9E%E4%B8%BB%E9%94%AE%20*%2F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyGenerator%20%3D%20Jdbc3KeyGenerator.INSTANCE%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyProperty%20%3D%20tableInfo.getKeyProperty()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyColumn%20%3D%20tableInfo.getKeyColumn()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20tableInfo.getKeySequence())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyGenerator%20%3D%20TableInfoHelper.genKeyGenerator(this.methodName%2C%20tableInfo%2C%20builderAssistant)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyProperty%20%3D%20tableInfo.getKeyProperty()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20keyColumn%20%3D%20tableInfo.getKeyColumn()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20String%20sql%20%3D%20String.format(sqlMethod.getSql()%2C%20tableInfo.getTableName()%2C%20columnScript%2C%20valuesScript)%3B%0A%20%20%20%20%20%20%20%20SqlSource%20sqlSource%20%3D%20languageDriver.createSqlSource(configuration%2C%20sql%2C%20modelClass)%3B%0A%20%20%20%20%20%20%20%20return%20this.addInsertMappedStatement(mapperClass%2C%20modelClass%2C%20getMethod(sqlMethod)%2C%20sqlSource%2C%20keyGenerator%2C%20keyProperty%2C%20keyColumn)%3B%0A%20%20%20%20%7D%0A%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * 批量新增数据,自选字段 insert\n * &lt;p> 不同的数据库支持度不一样!!!  只在 mysql 下测试过!!!  只在 mysql 下测试过!!!  只在 mysql 下测试过!!! &lt;\u002Fp>\n * &lt;p> 除了主键是 &lt;strong> 数据库自增的未测试 &lt;\u002Fstrong> 外理论上都可以使用!!! &lt;\u002Fp>\n * &lt;p> 如果你使用自增有报错或主键值无法回写到entity,就不要跑来问为什么了,因为我也不知道!!! &lt;\u002Fp>\n * &lt;p>\n * 自己的通用 mapper 如下使用:\n * &lt;pre>\n * int insertBatchSomeColumn(List&lt;T> entityList);\n * &lt;\u002Fpre>\n * &lt;\u002Fp>\n *\n * &lt;li> 注意: 这是自选字段 insert !!,如果个别字段在 entity 里为 null 但是数据库中有配置默认值, insert 后数据库字段是为 null 而不是默认值 &lt;\u002Fli>\n *\n * &lt;p>\n * 常用的 {@link Predicate}:\n * &lt;\u002Fp>\n *\n * &lt;li> 例1: t -> !t.isLogicDelete() , 表示不要逻辑删除字段 &lt;\u002Fli>\n * &lt;li> 例2: t -> !t.getProperty().equals(\"version\") , 表示不要字段名为 version 的字段 &lt;\u002Fli>\n * &lt;li> 例3: t -> t.getFieldFill() != FieldFill.UPDATE) , 表示不要填充策略为 UPDATE 的字段 &lt;\u002Fli>\n *\n * @author miemie\n * @since 2018-11-29\n *\u002F\u003C\u002Fspan>\n\n\u003Cspan class=\"token annotation punctuation\">@SuppressWarnings\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"serial\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">class\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSomeColumn\u003C\u002Fspan> \u003Cspan class=\"token keyword\">extends\u003C\u002Fspan> \u003Cspan class=\"token class-name\">AbstractMethod\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n\n    \u003Cspan class=\"token comment\">\u002F**\n     * 字段筛选条件\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token annotation punctuation\">@Setter\u003C\u002Fspan>\n    \u003Cspan class=\"token annotation punctuation\">@Accessors\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>chain \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token boolean\">true\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Predicate\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">TableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\n    \u003Cspan class=\"token comment\">\u002F**\n     * 默认方法名\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \t\u003Cspan class=\"token comment\">\u002F\u002F 方法名\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">super\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"insertBatchSomeColumn\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n    \u003Cspan class=\"token comment\">\u002F**\n     * 默认方法名\n     *\n     * @param predicate 字段筛选条件\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">Predicate\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">TableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">super\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"insertBatchSomeColumn\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>predicate \u003Cspan class=\"token operator\">=\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n    \u003Cspan class=\"token comment\">\u002F**\n     * @param name      方法名\n     * @param predicate 字段筛选条件\n     * @since 3.5.0\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">String\u003C\u002Fspan> name\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Predicate\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">TableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">super\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>name\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>predicate \u003Cspan class=\"token operator\">=\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n    \u003Cspan class=\"token annotation punctuation\">@SuppressWarnings\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"Duplicates\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n    \u003Cspan class=\"token annotation punctuation\">@Override\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">MappedStatement\u003C\u002Fspan> \u003Cspan class=\"token function\">injectMappedStatement\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">Class\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token operator\">?\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> mapperClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Class\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token operator\">?\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> modelClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">TableInfo\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">KeyGenerator\u003C\u002Fspan> keyGenerator \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">NoKeyGenerator\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token constant\">INSTANCE\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">SqlMethod\u003C\u002Fspan> sqlMethod \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">SqlMethod\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token constant\">INSERT_ONE\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">TableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> fieldList \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getFieldList\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> insertSqlColumn \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyInsertSqlColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token boolean\">true\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token boolean\">false\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan>\n            \u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">filterTableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>fieldList\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">TableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token operator\">::\u003C\u002Fspan>\u003Cspan class=\"token function\">getInsertSqlColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token constant\">EMPTY\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> columnScript \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token constant\">LEFT_BRACKET\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> insertSqlColumn\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">substring\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> insertSqlColumn\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">length\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">-\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> \u003Cspan class=\"token constant\">RIGHT_BRACKET\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> insertSqlProperty \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyInsertSqlProperty\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token boolean\">true\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token constant\">ENTITY_DOT\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token boolean\">false\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan>\n            \u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">filterTableFieldInfo\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>fieldList\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> predicate\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> i \u003Cspan class=\"token operator\">->\u003C\u002Fspan> i\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getInsertSqlProperty\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token constant\">ENTITY_DOT\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token constant\">EMPTY\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        insertSqlProperty \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token constant\">LEFT_BRACKET\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> insertSqlProperty\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">substring\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> insertSqlProperty\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">length\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">-\u003C\u002Fspan> \u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> \u003Cspan class=\"token constant\">RIGHT_BRACKET\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> valuesScript \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">SqlScriptUtils\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">convertForeach\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>insertSqlProperty\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token string\">\"list\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token keyword\">null\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token constant\">ENTITY\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token constant\">COMMA\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> keyProperty \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">null\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> keyColumn \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">null\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token comment\">\u002F\u002F 表包含主键处理逻辑,如果不包含主键当普通字段处理\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">if\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">havePK\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n            \u003Cspan class=\"token keyword\">if\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getIdType\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">==\u003C\u002Fspan> \u003Cspan class=\"token class-name\">IdType\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token constant\">AUTO\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n                \u003Cspan class=\"token comment\">\u002F* 自增主键 *\u002F\u003C\u002Fspan>\n                keyGenerator \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">Jdbc3KeyGenerator\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token constant\">INSTANCE\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n                keyProperty \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyProperty\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n                keyColumn \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan> \u003Cspan class=\"token keyword\">else\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n                \u003Cspan class=\"token keyword\">if\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">null\u003C\u002Fspan> \u003Cspan class=\"token operator\">!=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeySequence\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n                    keyGenerator \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">TableInfoHelper\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">genKeyGenerator\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>methodName\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> builderAssistant\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n                    keyProperty \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyProperty\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n                    keyColumn \u003Cspan class=\"token operator\">=\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getKeyColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n                \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n            \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n        \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">String\u003C\u002Fspan> sql \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">String\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">format\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>sqlMethod\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getSql\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> tableInfo\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">getTableName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> columnScript\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> valuesScript\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">SqlSource\u003C\u002Fspan> sqlSource \u003Cspan class=\"token operator\">=\u003C\u002Fspan> languageDriver\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">createSqlSource\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>configuration\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> sql\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> modelClass\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">return\u003C\u002Fspan> \u003Cspan class=\"token keyword\">this\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">addInsertMappedStatement\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>mapperClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> modelClass\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token function\">getMethod\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>sqlMethod\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> sqlSource\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> keyGenerator\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> keyProperty\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> keyColumn\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch3 id=\"toc-8\">配置 SQL 注入器\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>config\u003C\u002Fcode> 包下创建 \u003Ccode>MybatisPlusConfig\u003C\u002Fcode> 配置类：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%40Author%3A%20%E5%BC%A0%E4%B8%89%0A%20*%20%40From%3A%20%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%9A%E5%BC%A0%E4%B8%89%2C%20%E7%BD%91%E7%AB%99%EF%BC%9Awww.mashangan.com%0A%20*%20%40Date%3A%202022-12-15%2018%3A29%0A%20*%20%40Version%3A%20v1.0.0%0A%20*%20%40Description%3A%20TODO%0A%20**%2F%0A%40Configuration%0A%40MapperScan(%22com.mashangan.mybatisplusdemo.mapper%22)%0Apublic%20class%20MybatisPlusConfig%20%7B%0A%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%87%AA%E5%AE%9A%E4%B9%89%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%20SQL%20%E6%B3%A8%E5%85%A5%E5%99%A8%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20InsertBatchSqlInjector%20insertBatchSqlInjector()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20InsertBatchSqlInjector()%3B%0A%20%20%20%20%7D%0A%0A%7D%0A%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * @Author: 张三\n * @Date: 2022-12-15 18:29\n * @Version: v1.0.0\n * @Description: TODO\n **\u002F\u003C\u002Fspan>\n\u003Cspan class=\"token annotation punctuation\">@Configuration\u003C\u002Fspan>\n\u003Cspan class=\"token annotation punctuation\">@MapperScan\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"com.mashangan.mybatisplusdemo.mapper\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">class\u003C\u002Fspan> \u003Cspan class=\"token class-name\">MybatisPlusConfig\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n\n\n    \u003Cspan class=\"token comment\">\u002F**\n     * 自定义批量插入 SQL 注入器\n     *\u002F\u003C\u002Fspan>\n    \u003Cspan class=\"token annotation punctuation\">@Bean\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSqlInjector\u003C\u002Fspan> \u003Cspan class=\"token function\">insertBatchSqlInjector\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">return\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">InsertBatchSqlInjector\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch3 id=\"toc-9\">新建 MyBaseMapper\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>config\u003C\u002Fcode> 包下创建 \u003Ccode>MyBaseMapper\u003C\u002Fcode> 接口，让其继承自 Mybatis Plus 提供的 \u003Ccode>BaseMapper\u003C\u002Fcode>, 并定义批量插入方法：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%40author%3A%20%E5%BC%A0%E4%B8%89%0A%20*%20%40from%3A%20%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%9A%E5%BC%A0%E4%B8%89%2C%20%E7%BD%91%E7%AB%99%EF%BC%9Awww.mashangan.com%0A%20*%20%40date%3A%202022-12-13%2014%3A13%0A%20*%20%40version%3A%20v1.0.0%0A%20*%20%40description%3A%20TODO%0A%20**%2F%0Apublic%20interface%20MyBaseMapper%3CT%3E%20extends%20BaseMapper%3CT%3E%20%7B%0A%0A%09%2F%2F%20%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%0A%20%20%20%20int%20insertBatchSomeColumn(%40Param(%22list%22)%20List%3CT%3E%20batchList)%3B%0A%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">interface\u003C\u002Fspan> \u003Cspan class=\"token class-name\">MyBaseMapper\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">T\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token keyword\">extends\u003C\u002Fspan> \u003Cspan class=\"token class-name\">BaseMapper\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">T\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n\n\t\u003Cspan class=\"token comment\">\u002F\u002F 批量插入\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">int\u003C\u002Fspan> \u003Cspan class=\"token function\">insertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token annotation punctuation\">@Param\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"list\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">T\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> batchList\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cblockquote>\n\u003Cp>注意：方法名必须为 \u003Ccode>insertBatchSomeColumn\u003C\u002Fcode>, 和 \u003Ccode>InsertBatchSomeColumn\u003C\u002Fcode> 内部定义好的方法名保持一致。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch3 id=\"toc-10\">新建 UserMapper\u003C\u002Fh3>\n\u003Cp>在 \u003Ccode>mapper\u003C\u002Fcode> 包下创建 \u003Ccode>UserMapper\u003C\u002Fcode> 接口，注意继承刚刚自定义的 \u003Ccode>MyBaseMapper\u003C\u002Fcode>, 而不是 \u003Ccode>BaseMapper\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%2F**%0A%20*%20%40author%3A%20%E5%BC%A0%E4%B8%89%0A%20*%20%40from%3A%20%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%9A%E5%BC%A0%E4%B8%89%2C%20%E7%BD%91%E7%AB%99%EF%BC%9Awww.mashangan.com%0A%20*%20%40date%3A%202022-12-13%2014%3A13%0A%20*%20%40version%3A%20v1.0.0%0A%20*%20%40description%3A%20TODO%0A%20**%2F%0Apublic%20interface%20UserMapper%20extends%20MyBaseMapper%3CUser%3E%20%7B%0A%7D%0A%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token comment\">\u002F**\n * @author: 张三\n * @date: 2022-12-13 14:13\n * @version: v1.0.0\n * @description: TODO\n **\u002F\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">public\u003C\u002Fspan> \u003Cspan class=\"token keyword\">interface\u003C\u002Fspan> \u003Cspan class=\"token class-name\">UserMapper\u003C\u002Fspan> \u003Cspan class=\"token keyword\">extends\u003C\u002Fspan> \u003Cspan class=\"token class-name\">MyBaseMapper\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch2 id=\"toc-11\">测试批量插入\u003C\u002Fh2>\n\u003Cp>完成上面这些工作后，就可以使用 Mybatis Plus 提供的批量插入功能了。我们新建一个单元测试，并注入 \u003Ccode>UserMapper\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%40Autowired%0Aprivate%20UserMapper%20userMapper%3B%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token annotation punctuation\">@Autowired\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">private\u003C\u002Fspan> \u003Cspan class=\"token class-name\">UserMapper\u003C\u002Fspan> userMapper\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>单元测试如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%40Test%0Avoid%20testInsertBatch()%20%7B%0A%20%20%20%20List%3CUser%3E%20users%20%3D%20new%20ArrayList%3C%3E()%3B%0A%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%203%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20%20%20%20%20user.setName(%22%E5%BC%A0%E4%B8%89%22%20%2B%20i)%3B%0A%20%20%20%20%20%20%20%20user.setAge(i)%3B%0A%20%20%20%20%20%20%20%20user.setGender(1)%3B%0A%20%20%20%20%20%20%20%20users.add(user)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20userMapper.insertBatchSomeColumn(users)%3B%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token annotation punctuation\">@Test\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">void\u003C\u002Fspan> \u003Cspan class=\"token function\">testInsertBatch\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> users \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">ArrayList\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">for\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">int\u003C\u002Fspan> i \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i \u003Cspan class=\"token operator\">&lt;\u003C\u002Fspan> \u003Cspan class=\"token number\">3\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">User\u003C\u002Fspan> user \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"张三\"\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setAge\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setGender\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        users\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">add\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>user\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n    userMapper\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">insertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>users\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Cp>控制台实际执行 SQL 如下：\u003C\u002Fp>\n\u003Cp>\n\u003Cdiv class=\"img-loading\">\u003Cimg src=\"\u002Fupload\u002F167292369282647-hkCh.jpg\" loading=\"lazy\">\u003C\u002Fdiv>\n\u003C\u002Fp>\n\u003Cp>可以看到这次是真实的批量插入了，舒服了~\u003C\u002Fp>\n\u003Ch2 id=\"toc-12\">性能对比\u003C\u002Fh2>\n\u003Cp>我们来测试一下插入 105000  条数据，分别使用 \u003Ccode>for\u003C\u002Fcode> 循环插入数据、\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入、与真实批量插入三种模式，看看耗时差距多少。\u003C\u002Fp>\n\u003Cp>这里的机器配置如下：\u003C\u002Fp>\n\u003Cp>\n\u003Cdiv class=\"img-loading\">\u003Cimg src=\"\u002Fupload\u002F167292550362580-Ukgp.jpg\" loading=\"lazy\">\u003C\u002Fdiv>\n\u003C\u002Fp>\n\u003Ch3 id=\"toc-13\">\u003Ccode>for\u003C\u002Fcode> 循环插入\u003C\u002Fh3>\n\u003Cp>单元测试代码如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%40Test%0Avoid%20testInsert1()%20%7B%0A%20%20%20%20%2F%2F%20%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A722963%20ms%2C%20%E7%BA%A6%2012%20%E5%88%86%E9%92%9F%0A%20%20%20%20long%20start%20%3D%20System.currentTimeMillis()%3B%0A%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20105000%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20%20%20%20%20user.setName(%22%E5%BC%A0%E4%B8%89%22%20%2B%20i)%3B%0A%20%20%20%20%20%20%20%20user.setAge(i)%3B%0A%20%20%20%20%20%20%20%20user.setGender(1)%3B%0A%20%20%20%20%20%20%20%20userMapper.insert(user)%3B%0A%20%20%20%20%7D%0A%20%20%20%20System.out.println(String.format(%22%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A%25s%20ms%22%2C%20System.currentTimeMillis()%20-%20start))%3B%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token annotation punctuation\">@Test\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">void\u003C\u002Fspan> \u003Cspan class=\"token function\">testInsert1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F\u002F 总耗时：722963 ms, 约 12 分钟\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">long\u003C\u002Fspan> start \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">for\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">int\u003C\u002Fspan> i \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i \u003Cspan class=\"token operator\">&lt;\u003C\u002Fspan> \u003Cspan class=\"token number\">105000\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">User\u003C\u002Fspan> user \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"张三\"\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setAge\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setGender\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        userMapper\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">insert\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>user\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n    \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>out\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">println\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">String\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">format\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"总耗时：%s ms\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">-\u003C\u002Fspan> start\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch3 id=\"toc-14\">\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入\u003C\u002Fh3>\n\u003Cp>单元测试代码如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%40Test%0Avoid%20testInsert2()%20%7B%0A%20%20%20%20%2F%2F%20%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A95864%20ms%2C%20%E7%BA%A6%E4%B8%80%E5%88%86%E9%92%9F30%E7%A7%92%E5%B7%A6%E5%8F%B3%0A%20%20%20%20long%20start%20%3D%20System.currentTimeMillis()%3B%0A%20%20%20%20List%3CUser%3E%20users%20%3D%20new%20ArrayList%3C%3E()%3B%0A%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20105000%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20%20%20%20%20user.setName(%22%E5%BC%A0%E4%B8%89%22%20%2B%20i)%3B%0A%20%20%20%20%20%20%20%20user.setAge(i)%3B%0A%20%20%20%20%20%20%20%20user.setGender(1)%3B%0A%20%20%20%20%20%20%20%20users.add(user)%3B%0A%20%20%20%20%7D%0A%20%20%20%20userService.saveBatch(users)%3B%0A%20%20%20%20System.out.println(String.format(%22%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A%25s%20ms%22%2C%20System.currentTimeMillis()%20-%20start))%3B%0A%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token annotation punctuation\">@Test\u003C\u002Fspan>\n\u003Cspan class=\"token keyword\">void\u003C\u002Fspan> \u003Cspan class=\"token function\">testInsert2\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n    \u003Cspan class=\"token comment\">\u002F\u002F 总耗时：95864 ms, 约一分钟30秒左右\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">long\u003C\u002Fspan> start \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> users \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">ArrayList\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">for\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">int\u003C\u002Fspan> i \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i \u003Cspan class=\"token operator\">&lt;\u003C\u002Fspan> \u003Cspan class=\"token number\">105000\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">User\u003C\u002Fspan> user \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"张三\"\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setAge\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setGender\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        users\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">add\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>user\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n    userService\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">saveBatch\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>users\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>out\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">println\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">String\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">format\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"总耗时：%s ms\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">-\u003C\u002Fspan> start\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n\u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch3 id=\"toc-15\">真实批量插入\u003C\u002Fh3>\n\u003Cp>注意，\u003Cstrong>真实业务场景下，也不可能会将 10 万多条记录组装成一条 SQL 进行批量插入\u003C\u002Fstrong>，因为数据库对执行 SQL 大小是有限制的（这个数值可以自行设置），还是需要分片插入，比如取 1000 条执行一次批量插入，单元测试代码如下：\u003C\u002Fp>\n\u003Cdiv class=\"language-java\" data-ext=\"java\" data-code=\"%40Test%0A%20%20%20%20void%20testInsertBatch1()%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A6320%20ms%2C%20%E7%BA%A6%206%20%E7%A7%92%0A%20%20%20%20%20%20%20%20long%20start%20%3D%20System.currentTimeMillis()%3B%0A%20%20%20%20%20%20%20%20List%3CUser%3E%20users%20%3D%20new%20ArrayList%3C%3E()%3B%0A%20%20%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20105000%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20user.setName(%22%E5%BC%A0%E4%B8%89%22%20%2B%20i)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20user.setAge(i)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20user.setGender(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20users.add(user)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20%E5%88%86%E7%89%87%E6%8F%92%E5%85%A5%EF%BC%88%E6%AF%8F%201000%20%E6%9D%A1%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AC%A1%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%EF%BC%89%0A%20%20%20%20%20%20%20%20int%20batchSize%20%3D%201000%3B%0A%20%20%20%20%20%20%20%20int%20total%20%3D%20users.size()%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E9%9C%80%E8%A6%81%E6%89%A7%E8%A1%8C%E7%9A%84%E6%AC%A1%E6%95%B0%0A%20%20%20%20%20%20%20%20int%20insertTimes%20%3D%20total%20%2F%20batchSize%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E6%89%A7%E8%A1%8C%E9%9C%80%E8%A6%81%E6%8F%90%E4%BA%A4%E7%9A%84%E8%AE%B0%E5%BD%95%E6%95%B0%EF%BC%88%E9%98%B2%E6%AD%A2%E5%8F%AF%E8%83%BD%E4%B8%8D%E8%B6%B3%201000%20%E6%9D%A1%EF%BC%89%0A%20%20%20%20%20%20%20%20int%20lastSize%20%3D%20batchSize%3B%0A%20%20%20%20%20%20%20%20if%20(total%20%25%20batchSize%20!%3D%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20insertTimes%2B%2B%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20lastSize%20%3D%20total%25batchSize%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20for%20(int%20j%20%3D%200%3B%20j%20%3C%20insertTimes%3B%20j%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(insertTimes%20%3D%3D%20j%2B1)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20batchSize%20%3D%20lastSize%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E5%88%86%E7%89%87%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%0A%20%20%20%20%20%20%20%20%20%20%20%20userMapper.insertBatchSomeColumn(users.subList(j*batchSize%2C%20(j*batchSize%2BbatchSize)))%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println(String.format(%22%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A%25s%20ms%22%2C%20System.currentTimeMillis()%20-%20start))%3B%0A%20%20%20%20%7D%0A\">\n        \u003Cbutton class=\"vp-copy-code-button\" data-copy data-copied=\"已复制\" aria-label=\"复制代码\">\u003C\u002Fbutton>\n        \u003Cpre>\u003Ccode class=\"language-java\">\u003Cspan class=\"token annotation punctuation\">@Test\u003C\u002Fspan>\n    \u003Cspan class=\"token keyword\">void\u003C\u002Fspan> \u003Cspan class=\"token function\">testInsertBatch1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n        \u003Cspan class=\"token comment\">\u002F\u002F 总耗时：6320 ms, 约 6 秒\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">long\u003C\u002Fspan> start \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">List\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan> users \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">ArrayList\u003C\u002Fspan>\u003Cspan class=\"token generics\">\u003Cspan class=\"token punctuation\">&lt;\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">for\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">int\u003C\u002Fspan> i \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i \u003Cspan class=\"token operator\">&lt;\u003C\u002Fspan> \u003Cspan class=\"token number\">105000\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> i\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n            \u003Cspan class=\"token class-name\">User\u003C\u002Fspan> user \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token keyword\">new\u003C\u002Fspan> \u003Cspan class=\"token class-name\">User\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setName\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"张三\"\u003C\u002Fspan> \u003Cspan class=\"token operator\">+\u003C\u002Fspan> i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setAge\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>i\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            user\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">setGender\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            users\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">add\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>user\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n        \u003Cspan class=\"token comment\">\u002F\u002F 分片插入（每 1000 条执行一次批量插入）\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">int\u003C\u002Fspan> batchSize \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">1000\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">int\u003C\u002Fspan> total \u003Cspan class=\"token operator\">=\u003C\u002Fspan> users\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">size\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token comment\">\u002F\u002F 需要执行的次数\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">int\u003C\u002Fspan> insertTimes \u003Cspan class=\"token operator\">=\u003C\u002Fspan> total \u003Cspan class=\"token operator\">\u002F\u003C\u002Fspan> batchSize\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token comment\">\u002F\u002F 最后一次执行需要提交的记录数（防止可能不足 1000 条）\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">int\u003C\u002Fspan> lastSize \u003Cspan class=\"token operator\">=\u003C\u002Fspan> batchSize\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token keyword\">if\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>total \u003Cspan class=\"token operator\">%\u003C\u002Fspan> batchSize \u003Cspan class=\"token operator\">!=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n            insertTimes\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            lastSize \u003Cspan class=\"token operator\">=\u003C\u002Fspan> total\u003Cspan class=\"token operator\">%\u003C\u002Fspan>batchSize\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n        \u003Cspan class=\"token keyword\">for\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token keyword\">int\u003C\u002Fspan> j \u003Cspan class=\"token operator\">=\u003C\u002Fspan> \u003Cspan class=\"token number\">0\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> j \u003Cspan class=\"token operator\">&lt;\u003C\u002Fspan> insertTimes\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan> j\u003Cspan class=\"token operator\">++\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n            \u003Cspan class=\"token keyword\">if\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>insertTimes \u003Cspan class=\"token operator\">==\u003C\u002Fspan> j\u003Cspan class=\"token operator\">+\u003C\u002Fspan>\u003Cspan class=\"token number\">1\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">{\u003C\u002Fspan>\n                batchSize \u003Cspan class=\"token operator\">=\u003C\u002Fspan> lastSize\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n            \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\n            \u003Cspan class=\"token comment\">\u002F\u002F 分片执行批量插入\u003C\u002Fspan>\n            userMapper\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">insertBatchSomeColumn\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>users\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">subList\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>j\u003Cspan class=\"token operator\">*\u003C\u002Fspan>batchSize\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>j\u003Cspan class=\"token operator\">*\u003C\u002Fspan>batchSize\u003Cspan class=\"token operator\">+\u003C\u002Fspan>batchSize\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n        \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n        \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>out\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">println\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token class-name\">String\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">format\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token string\">\"总耗时：%s ms\"\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">,\u003C\u002Fspan> \u003Cspan class=\"token class-name\">System\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">.\u003C\u002Fspan>\u003Cspan class=\"token function\">currentTimeMillis\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">(\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan> \u003Cspan class=\"token operator\">-\u003C\u002Fspan> start\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">)\u003C\u002Fspan>\u003Cspan class=\"token punctuation\">;\u003C\u002Fspan>\n    \u003Cspan class=\"token punctuation\">}\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n      \u003C\u002Fdiv>\n\u003Ch3 id=\"toc-16\">耗时对比\u003C\u002Fh3>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>方式\u003C\u002Fth>\n\u003Cth>总耗时\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>for\u003C\u002Fcode> 循环插入\u003C\u002Ftd>\n\u003Ctd>722963 ms, 约 12 分钟\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>savaBatch()\u003C\u002Fcode> 伪批量插入\u003C\u002Ftd>\n\u003Ctd>95864 ms, 约一分钟30秒左右\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>真实批量插入\u003C\u002Ftd>\n\u003Ctd>6320 ms, 约 6 秒\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>耗时对比非常直观，在大批量数据新增的场景下，批量插入性能最高。\u003C\u002Fp>\n\u003Ch2 id=\"toc-17\">结语\u003C\u002Fh2>\n\u003Cp>本小节中，我们学习了如何通过 Mybatis Plus 的 SQL 注入器实现真实的批量插入，同时最后还对比了三种不同方式插入 10 万多数据的耗时，很直观的看到在海量数据场景下，批量插入的性能是最强的。\u003C\u002Fp>"]