专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

MybatisPlus批量插入这样操作提升性能

  使用的mybatisplus的批量插入方法:saveBatch(),之前就看到过网上都在说在jdbc的url路径上加上rewriteBatchedStatementstrue参数mysql底层才能开启真正的批量插入模式。
  保证5。1。13以上版本的驱动,才能实现高性能的批量插入。MySQLJDBC驱动在默认情况下会无视executeBatch()语句,把我们期望批量执行的一组sql语句拆散,一条一条地发给MySQL数据库,批量插入实际上是单条插入,直接造成较低的性能。只有把rewriteBatchedStatements参数置为true,驱动才会帮你批量执行SQL。另外这个选项对INSERTUPDATEDELETE都有效。
  目前我的数据表目前是没有建立索引的,即使是在1000来w的数据量下进行1500条的批量插入也不可能消耗20来秒吧,于是矛盾转移到saveBatch方法,使用版本:
  查看源码:publicbooleansaveBatch(CollectionTentityList,intbatchSize){StringsqlStatementthis。getSqlStatement(SqlMethod。INSERTONE);returnthis。executeBatch(entityList,batchSize,(sqlSession,entity){sqlSession。insert(sqlStatement,entity);});}protectedEbooleanexecuteBatch(CollectionElist,intbatchSize,BiConsumerSqlSession,Econsumer){returnSqlHelper。executeBatch(this。entityClass,this。log,list,batchSize,consumer);}publicstaticEbooleanexecuteBatch(Classlt;?entityClass,Loglog,CollectionElist,intbatchSize,BiConsumerSqlSession,Econsumer){Assert。isFalse(batchSize1,batchSizemustnotbelessthanone,newObject〔0〕);return!CollectionUtils。isEmpty(list)executeBatch(entityClass,log,(sqlSession){intsizelist。size();inti1;for(Iteratorvar6list。iterator();var6。hasNext();i){Eelementvar6。next();consumer。accept(sqlSession,element);if(ibatchSize0isize){sqlSession。flushStatements();}}});}
  最终来到了executeBatch()方法,可以看到这很明显是在一条一条循环插入,通过sqlSession。flushStatements()将一个个单条插入的insert语句分批次进行提交,而且是同一个sqlSession,这相比遍历集合循环insert来说有一定的性能提升,但是这并不是sql层面真正的批量插入。
  通过查阅相关文档后,发现mybatisPlus提供了sql注入器,我们可以自定义方法来满足业务的实际开发需求。
  sql注入器官网
  https:baomidou。compages42ea4a
  sql注入器官方示例
  https:gitee。combaomidoumybatisplussamplestreemastermybatisplussampledeluxe
  在mybtisPlus的核心包下提供的默认可注入方法有这些:
  在扩展包下,mybatisPlus还为我们提供了可扩展的可注入方法:
  AlwaysUpdateSomeColumnById:根据Id更新每一个字段,全量更新不忽略null字段,解决mybatisplus中updateById默认会自动忽略实体中null值字段不去更新的问题;InsertBatchSomeColumn:真实批量插入,通过单SQL的insert语句实现批量插入;Upsert:更新or插入,根据唯一约束判断是执行更新还是删除,相当于提供insertonduplicatekeyupdate支持。
  可以发现mybatisPlus已经提供好了InsertBatchSomeColumn的方法,我们只需要把这个方法添加进我们的sql注入器即可。publicMappedStatementinjectMappedStatement(Classlt;?mapperClass,Classlt;?modelClass,TableInfotableInfo){KeyGeneratorkeyGeneratorNoKeyGenerator。INSTANCE;SqlMethodsqlMethodSqlMethod。INSERTONE;ListTableFieldInfofieldListtableInfo。getFieldList();StringinsertSqlColumntableInfo。getKeyInsertSqlColumn(true,false)this。filterTableFieldInfo(fieldList,this。predicate,TableFieldInfo::getInsertSqlColumn,);拼接批量插入语句StringcolumnScript(insertSqlColumn。substring(0,insertSqlColumn。length()1));StringinsertSqlPropertytableInfo。getKeyInsertSqlProperty(true,et。,false)this。filterTableFieldInfo(fieldList,this。predicate,(i){returni。getInsertSqlProperty(et。);},);insertSqlProperty(insertSqlProperty。substring(0,insertSqlProperty。length()1));StringvaluesScriptSqlScriptUtils。convertForeach(insertSqlProperty,list,(String)null,et,,);StringkeyPropertynull;StringkeyColumnnull;if(tableInfo。havePK()){if(tableInfo。getIdType()IdType。AUTO){keyGeneratorJdbc3KeyGenerator。INSTANCE;keyPropertytableInfo。getKeyProperty();keyColumntableInfo。getKeyColumn();}elseif(null!tableInfo。getKeySequence()){keyGeneratorTableInfoHelper。genKeyGenerator(this。getMethod(sqlMethod),tableInfo,this。builderAssistant);keyPropertytableInfo。getKeyProperty();keyColumntableInfo。getKeyColumn();}}StringsqlString。format(sqlMethod。getSql(),tableInfo。getTableName(),columnScript,valuesScript);SqlSourcesqlSourcethis。languageDriver。createSqlSource(this。configuration,sql,modelClass);returnthis。addInsertMappedStatement(mapperClass,modelClass,this。getMethod(sqlMethod),sqlSource,(KeyGenerator)keyGenerator,keyProperty,keyColumn);}接下来就通过SQL注入器实现真正的批量插入默认的sql注入器publicclassDefaultSqlInjectorextendsAbstractSqlInjector{publicDefaultSqlInjector(){}publicListgetMethodList(Classlt;?mapperClass,TableInfotableInfo){if(tableInfo。havePK()){return(List)Stream。of(newInsert(),newDelete(),newDeleteByMap(),newDeleteById(),newDeleteBatchByIds(),newUpdate(),newUpdateById(),newSelectById(),newSelectBatchByIds(),newSelectByMap(),newSelectCount(),newSelectMaps(),newSelectMapsPage(),newSelectObjs(),newSelectList(),newSelectPage())。collect(Collectors。toList());}else{this。logger。warn(String。format(s,NotfoundTableIdannotation,CannotuseMybatisPlusxxByIdMethod。,tableInfo。getEntityType()));return(List)Stream。of(newInsert(),newDelete(),newDeleteByMap(),newUpdate(),newSelectByMap(),newSelectCount(),newSelectMaps(),newSelectMapsPage(),newSelectObjs(),newSelectList(),newSelectPage())。collect(Collectors。toList());}}}继承DefaultSqlInjector自定义sql注入器authorzhmskydate202281515:13publicclassMySqlInjectorextendsDefaultSqlInjector{OverridepublicListgetMethodList(Classlt;?mapperClass){ListmethodListsuper。getMethodList(mapperClass);更新时自动填充的字段,不用插入值methodList。add(newInsertBatchSomeColumn(ii。getFieldFill()!FieldFill。UPDATE));returnmethodList;}}将自定义的sql注入器注入到Mybatis容器中authorzhmskydate202281515:15ConfigurationpublicclassMybatisPlusConfig{BeanpublicMySqlInjectorsqlInjector(){returnnewMySqlInjector();}}继承BaseMapper添加自定义方法authorzhmskydate202281515:17publicinterfaceCommonMapperTextendsBaseMapperT{真正的批量插入paramentityListreturnintinsertBatchSomeColumn(ListTentityList);}对应的mapper层接口继承上面自定义的mapperauthorzhmskysince20211201MapperpublicinterfaceUserMapperextendsCommonMapperUser{}
  最后直接调用UserMapper的insertBatchSomeColumn()方法即可实现真正的批量插入。TestvoidcontextLoads(){for(inti0;i5;i){UserusernewUser();user。setAge(10);user。setUsername(zhmsky);user。setEmail(21575559qq。com);userList。add(user);}longlSystem。currentTimeMillis();userMapper。insertBatchSomeColumn(userList);longl1System。currentTimeMillis();System。out。println(:(l1l));userList。clear();}
  查看日志输出信息,观察执行的sql语句;
  发现这才是真正意义上的sql层面的批量插入。
  但是,到这里并没有结束,mybatisPlus官方提供的insertBatchSomeColumn方法不支持分批插入,也就是有多少直接全部一次性插入,这就可能会导致最后的sql拼接语句特别长,超出了mysql的限制,于是我们还要实现一个类似于saveBatch的分批的批量插入方法。另外,搜索公众号Linux就该这样学后台回复猴子,获取一份惊喜礼包。添加分批插入
  模仿原来的saveBatch方法:authorzhmskysince20211201ServicepublicclassUserServiceImplextendsServiceImplUserMapper,UserimplementsUserService{OverrideTransactional(rollbackFor{Exception。class})publicbooleansaveBatch(CollectionUserentityList,intbatchSize){try{intsizeentityList。size();intidxLimitMath。min(batchSize,size);inti1;保存单批提交的数据集合ListUseroneBatchListnewArrayList();for(IteratorUservar7entityList。iterator();var7。hasNext();i){Userelementvar7。next();oneBatchList。add(element);if(iidxLimit){baseMapper。insertBatchSomeColumn(oneBatchList);每次提交后需要清空集合数据oneBatchList。clear();idxLimitMath。min(idxLimitbatchSize,size);}}}catch(Exceptione){log。error(saveBatchfail,e);returnfalse;}returntrue;}}
  测试:TestvoidcontextLoads(){for(inti0;i20;i){UserusernewUser();user。setAge(10);user。setUsername(zhmsky);user。setEmail(21575559qq。com);userList。add(user);}longlSystem。currentTimeMillis();userService。saveBatch(userList,10);longl1System。currentTimeMillis();System。out。println(:(l1l));userList。clear();}
  输出结果:
  分批插入已满足,到此收工结束了。接下来最重要的测试下性能
  当前数据表的数据量在100w多条,在此基础上分别拿原始的saveBatch(假的批量插入)和insertBatchSomeColumn(真正的批量插入)进行性能对比(jdbc均开启rewriteBatchedStatements):
  原来的假的批量插入:Testvoidinsert(){for(inti0;i50000;i){UserusernewUser();
  自定义的insertBatchSomeColumn:TestvoidcontextLoads(){for(inti0;i50000;i){UserusernewUser
  分批插入5w条数据,自定义的真正意义上的批量插入耗时减少了3秒左右,用insertBatchSomeColum分批插入1500条数据耗时650毫秒,这速度已经挺快了

德国历史最佳阵容诺伊尔穆勒只能当替补,世界杯三连冠起步?德国队是世界足坛的老牌强队,曾四夺世界杯冠军,三次问鼎欧锦赛冠军,有着悠久的历史和光荣的传统。曾涌现出无数的世界级巨星,球员身体素质出众,战术素养极高,作风顽强,不到最后绝不放弃,9。1收评,大盘极度缩量即将变盘向上,明天是上涨的时间窗口期下午好!马上收盘了,我来做一下今天的盘面解析!1。马上收盘!今天大盘全天震荡,涨跌幅度并不大,相反这个震荡也是给到了大家起涨前的低吸机会,而今天量能萎缩至极致,也是近期以来的最小成封面科技周报华为Mate50将支持卫星通信微信输入法已在测试行业一周大事东方甄选推独立APP,下载量已近20万近日,东方甄选推出了独立的APP,并已在各大应用商店上线。进入APP后可以看见,页面底部设有甄选分类购物车和我的订单这四大入口。在心脏病的治疗方法有哪些?三种习惯让你远离心脏病一药物治疗。药物治疗是心脏病最为基础的疗法。对于目前治疗心脏病的药物很普遍,因此只要严格按照医师的嘱咐,就能起到很好的治疗效果。药物治疗对于早期心脏病有很不错的功效,这样可以减少手9月1日A股收评高层护盘意图十分迫切!大盘止跌时间表已出炉黑周三后,A股市场再次遭遇黑周四,唯一值得庆幸的是,周四市场整体跌幅没有周三大。同时,让大家深套的赛道股,周四跌幅也有趋缓的迹象。这是因为从技术上看,绝大多数的赛道股连续挖坑后已经索尼Xperia5IV发布6。1英寸显示屏,5000mAh电池,1200万像素如期,索尼今天推出了Xperia5IV。这家日本电子巨头的最新紧凑型旗舰智能手机带来了有意义的升级。新型号提供更大的电池,无线充电支持和改进的相机。让我们看看它所提供的详细规格。索旗舰实力顶尖配置,vivo的高价高配手机,还真不好意思拒绝要知道不是所有人都喜欢中低端机型,对于很多土豪用户来说高端机型才是他们的心头好。几乎所有的手机品牌都有自己的高端旗舰产品,而vivoX80Pro就是vivo的高端旗舰。高端的体现可诺基亚C31手机将在国内上市,搭载紫光展锐28nm芯片IT之家9月2日消息,昨日晚间,HMDGlobal在海外发布了多款产品,包括诺基亚X30G60C31手机诺基亚T21平板电脑等。今日,诺基亚手机官方微博宣布,诺基亚C31入门级智能真香vivo终于跳水,天玑9000蔡司镜头自研芯片,仅3199元转眼之间已经是九月份,再过不久年度大戏要开场了,华为Mate50系列,苹果iPhone14系列都会发布,吸引到很多人的眼光,这个期间友商也很懂事,高端市场是玩不过他俩的,因此都在内暗黑破坏神不朽幽魂马车BOSS在哪里幽魂马车BOSS位置攻略在暗黑破坏神不朽中很多玩家还不清楚幽魂马车BOSS在哪里。接下来就让小编给大家带来暗黑破坏神不朽幽魂马车BOSS位置攻略,感兴趣的小伙伴们一起来看看吧。暗黑破坏神不朽幽魂马车BOS中国队惊险晋级U18女篮亚锦赛决赛新华社新德里9月10日电中国队10日在印度班加罗尔举行的亚洲U18女篮锦标赛半决赛中顶住日本队的末节反扑,以5451惊险胜出,将与澳大利亚队争夺冠军。中国队前三节建立起15分的领先
摊煎饼炒菜送菜机器人能成为餐馆得力干将吗?日前,市民在牛街地铁口体验煎饼机器人摊煎饼,自动机器人3分钟左右就能做出一套煎饼。本报记者吴镝摄近日,在地铁牛街站附近出现的一台煎饼机器人吸引众多市民围观体验。随着技术的进步,机器谁才是真的米饭杀手?这4道菜榜上有名,鲜香美味,香辣开胃米饭杀手指的是与米饭相搭配的炒菜,米饭在我们的餐桌上,一直作为主食的存在,搭配米饭不用山珍海味,也不用鸡鸭鱼肉,一道普通的家常小炒就够了,香飘满屋,诱人食欲,有时候听到一道菜的名字八九早餐怎么吃?看我15天记录,干稀搭配,好做又暖和头条创作挑战赛数九寒天了,每天吃什么多主妇来说是个考验,尤其是这个放开时期,既要吃好喝好,还要又营养美味,更有滋补信强,这样才能抵抗严寒和提高免疫力。尤其是早餐,是一天之中最早的一春季进补,不管有钱没钱,常给家人吃这菜,营养全面,增强抵抗力春耕进行时进入到春季以后,气温慢慢开始升温,南方人都开始穿短袖了,路边遍地都是野花和野草,小区的绿色植被都发芽了,空气非常清新,感觉春天太舒服了。春天是进补的黄金期,春天的天气变好2个鸡蛋,做出不会破皮的烫面蛋糕,松软细腻,甜香可口关注大胖友图图,每天都能看到新奇,简单,美味又实用的食谱哦今天我们试试用2个蛋做烫面蛋糕。你需要准备的材料有玉米油20克,低筋面粉30克,浓牛奶25克,鸡蛋2只,白糖30克先把玉米西葫芦别总炒着吃了,试试这样做,皮薄焦香,馅大很鲜美,不难学头条创作挑战赛大家好,我是Allie,美好的一天从营养早餐开始,吃好早餐,一整天都精力充沛。早餐吃好午餐吃饱晚餐吃少,低油低盐清淡饮食,这是我多年的习惯,希望和朋友们一起吃出健康吃当花甲遇到鸡,真是最佳搭档,麻辣鲜香太美味,准备好米饭,开整人们常说没有什么事情是一顿美食解决不了的,如果有,那就再吃两顿,虽然说得有些夸张,但确实美食是每个人都抵挡不了的。不论生活中遇到什么烦恼,美食都是人们最好的慰藉,味蕾上的满足能够让柳州夜市也太卷了吧!!!!说到柳州,许多人一定想到的是螺蛳粉。酸辣鲜香的螺蛳粉不仅是柳州人的心头爱,也早已声名远扬,征服了很多外地食客的味蕾,圈粉无数。每到假期,就有一大波全国游客慕名来柳州嗍粉。许多螺蛳粉(环境)林海雪原内蒙古森工集团满归森工公司乌龙岱林场地处大兴安岭深处。立春之后,大雪仍停驻在广袤林海间,别有特色。2月23日拍摄的内蒙古森工集团满归森工公司乌龙岱林场景色(无人机照片)。新华社记者2023年潍城区乡村文化旅游节启动2月25日上午,潍坊市潍城区组织召开乡村文化旅游节新闻发布会,介绍全区文化旅游和2023年乡村文化旅游节基本情况,并发布了乡村旅游推荐片,推出了旅游形象代言人。同步,启动2023年禅让制真的那么美好吗?还是只是一块遮羞布?帝舜扑朔迷离的死因美好的禅让制到底是在为谁遮羞?帝舜扑朔迷离的死因到底是什么?这样一个富有传奇色彩的人物为何不得善终?相传帝舜在位的第三十九年,也就是他一百岁的时候。他去了一趟南方巡视。不幸途中在苍
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网