iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >mybatisplus批量更新太慢该怎么解决
  • 308
分享到

mybatisplus批量更新太慢该怎么解决

2023-07-05 09:07:27 308人浏览 安东尼
摘要

这篇文章主要讲解了“mybatisplus批量更新太慢该怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mybatisplus批量更新太慢该怎么解决”吧!最近使用mybatis-plu

这篇文章主要讲解了“mybatisplus批量更新太慢该怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mybatisplus批量更新太慢该怎么解决”吧!

最近使用mybatis-plus的 saveOrUpdateBath 和saveBath接口执行特别慢,数据量大时往往需要十几分钟,打开日志查看原来批量操作也是循环单条数据插入的,那有没有批量更新的办法呢??

mybatis-plus 提供了一个自定义方法sql注入器DefaultSqlInjector我们可以通过继DefaultSqlInjector来加入自定义的方法达到批量插入的效果。

import com.baomidou.mybatisplus.core.injector.AbstractMethod;import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;import org.springframework.stereotype.Component; import java.util.List; @Componentpublic class CustomizedSqlInjector  extends DefaultSqlInjector {        @Override    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {        List<AbstractMethod> methodList = super.getMethodList(mapperClass);        methodList.add(new InsertBatchMethod());       // methodList.add(new UpdateBatchMethod());        methodList.add(new MysqlInsertOrUpdateBath());        methodList.add(new PGInsertOrUpdateBath());        return methodList;    } }

同时我们需要继承BaseMapper<T> 定义

 import com.baomidou.mybatisplus.core.mapper.BaseMapper;import org.apache.ibatis.annotations.Param; import java.util.List;public interface RootMapper<T> extends BaseMapper<T> {        int insertBatch(@Param("list") List<T> list);        int MysqlInsertOrUpdateBatch(@Param("list") List<T> list);     int pgInsertOrUpdateBatch(@Param("list") List<T> list);}

在需要使用批量更新插入的mapper上使用自定义的RootMapper

如下图

import com.XX.edu.common.batchOperation.RootMapper;import com.XX.edu.exam.model.TScore;import org.springframework.stereotype.Repository; @Repositorypublic interface TScoreMapper extends RootMapper<TScore> { }

下面我们来定义批量插入的方法:

package com.XX.edu.common.batchOperation; import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.core.enums.SqlMethod;import com.baomidou.mybatisplus.core.injector.AbstractMethod;import com.baomidou.mybatisplus.core.metadata.TableInfo;import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;import org.apache.commons.lang3.StringUtils;import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;import org.apache.ibatis.executor.keygen.KeyGenerator;import org.apache.ibatis.executor.keygen.NoKeyGenerator;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.mapping.SqlSource;import org.slf4j.Logger;import org.slf4j.LoggerFactory; public class InsertBatchMethod extends AbstractMethod {    Logger logger = LoggerFactory.getLogger(getClass());     @Override    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {        final String sql = "<script>insert into %s %s values %s</script>";        final String fieldSql = prepareFieldSql(tableInfo);        final String valueSql = prepareValuesSql(tableInfo);        final String sqlResult = String.fORMat(sql, tableInfo.getTableName(), fieldSql, valueSql);        logger.debug("sqlResult----->{}", sqlResult);        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);        KeyGenerator keyGenerator = new NoKeyGenerator();        SqlMethod sqlMethod = SqlMethod.INSERT_ONE;        String keyProperty = null;        String keyColumn = null;        // 表包含主键处理逻辑,如果不包含主键当普通字段处理        if (StringUtils.isNotEmpty(tableInfo.geTKEyProperty())) {            if (tableInfo.getIdType() == IdType.AUTO) {                                keyGenerator = new Jdbc3KeyGenerator();                keyProperty = tableInfo.getKeyProperty();                keyColumn = tableInfo.getKeyColumn();            } else {                if (null != tableInfo.getKeySequence()) {                    keyGenerator = TableInfoHelper.genKeyGenerator(sqlMethod.getMethod(),tableInfo, builderAssistant);                    keyProperty = tableInfo.getKeyProperty();                    keyColumn = tableInfo.getKeyColumn();                }            }        }        // 第三个参数必须和RootMapper的自定义方法名一致        return this.addInsertMappedStatement(mapperClass, modelClass, "insertBatch", sqlSource, keyGenerator, keyProperty, keyColumn);    }         private String prepareValuesSql(TableInfo tableInfo) {        final StringBuilder valueSql = new StringBuilder();        valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");        //valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");        tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));        valueSql.delete(valueSql.length() - 1, valueSql.length());        valueSql.append("</foreach>");        return valueSql.toString();    }         private String prepareFieldSql(TableInfo tableInfo) {        StringBuilder fieldSql = new StringBuilder();        //fieldSql.append(tableInfo.getKeyColumn()).append(",");        tableInfo.getFieldList().forEach(x -> {            fieldSql.append(x.getColumn()).append(",");        });        fieldSql.delete(fieldSql.length() - 1, fieldSql.length());        fieldSql.insert(0, "(");        fieldSql.append(")");        return fieldSql.toString();    }}

继续定义批量插入更新的抽象方法

package com.XX.edu.common.batchOperation; import com.baomidou.mybatisplus.core.injector.AbstractMethod;import com.baomidou.mybatisplus.core.metadata.TableInfo;import org.apache.ibatis.executor.keygen.NoKeyGenerator;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.mapping.SqlSource; public abstract class InsertOrUpdateBathAbstract extends AbstractMethod {    @Override    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {        final  SqlSource sqlSource = prepareSqlSource(tableInfo, modelClass);        // 第三个参数必须和RootMapper的自定义方法名一致        return this.addInsertMappedStatement(mapperClass, modelClass, prepareInsertOrUpdateBathName(), sqlSource, new NoKeyGenerator(), null, null);     }     protected abstract SqlSource prepareSqlSource(TableInfo tableInfo, Class<?> modelClass);        protected abstract String prepareInsertOrUpdateBathName(); }

继承上面的抽象类----mysql版本(本版本未测试 根据自己需求修改)

package com.XX.edu.common.batchOperation; import com.baomidou.mybatisplus.core.metadata.TableInfo;import org.apache.ibatis.mapping.SqlSource;import org.springframework.util.StringUtils; public class MysqlInsertOrUpdateBath extends InsertOrUpdateBathAbstract {     @Override    protected SqlSource prepareSqlSource(TableInfo tableInfo, Class<?> modelClass) {        final String sql = "<script>insert into %s %s values %s ON DUPLICATE KEY UPDATE %s</script>";        final String tableName = tableInfo.getTableName();        final String filedSql = prepareFieldSql(tableInfo);        final String modelValuesSql = prepareModelValuesSql(tableInfo);        final String duplicateKeySql = prepareDuplicateKeySql(tableInfo);        final String sqlResult = String.format(sql, tableName, filedSql, modelValuesSql, filedSql, duplicateKeySql);        //String.format(sql, tableName, filedSql, modelValuesSql, duplicateKeySql);        //System.out.println("savaorupdatesqlsql="+sqlResult);        return languageDriver.createSqlSource(configuration, sqlResult, modelClass);    }      @Override    protected String prepareInsertOrUpdateBathName() {        return "mysqlInsertOrUpdateBath";    }     String prepareDuplicateKeySql(TableInfo tableInfo) {        final StringBuilder duplicateKeySql = new StringBuilder();        if (!StringUtils.isEmpty(tableInfo.getKeyColumn())) {            duplicateKeySql.append(tableInfo.getKeyColumn()).append("=values(").append(tableInfo.getKeyColumn()).append("),");        }         tableInfo.getFieldList().forEach(x -> {            duplicateKeySql.append(x.getColumn())                    .append("=values(")                    .append(x.getColumn())                    .append("),");        });        duplicateKeySql.delete(duplicateKeySql.length() - 1, duplicateKeySql.length());        return duplicateKeySql.toString();    }     String prepareModelValuesSql(TableInfo tableInfo) {        final StringBuilder valueSql = new StringBuilder();        valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");        if (!StringUtils.isEmpty(tableInfo.getKeyProperty())) {            valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");        }        tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));        valueSql.delete(valueSql.length() - 1, valueSql.length());        valueSql.append("</foreach>");        return valueSql.toString();    }         String prepareFieldSql(TableInfo tableInfo) {        StringBuilder fieldSql = new StringBuilder();        fieldSql.append(tableInfo.getKeyColumn()).append(",");        tableInfo.getFieldList().forEach(x -> {            fieldSql.append(x.getColumn()).append(",");        });        fieldSql.delete(fieldSql.length() - 1, fieldSql.length());        fieldSql.insert(0, "(");        fieldSql.append(")");        return fieldSql.toString();    }}

继承上面的抽象类----postgresql版本(已测试完成,其中id使用序列自增)

package com.XX.edu.common.batchOperation; import com.baomidou.mybatisplus.core.metadata.TableInfo;import org.apache.ibatis.mapping.SqlSource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.util.StringUtils; public class PGInsertOrUpdateBath extends InsertOrUpdateBathAbstract {    Logger logger = LoggerFactory.getLogger(getClass());    @Override    protected SqlSource prepareSqlSource(TableInfo tableInfo, Class<?> modelClass) {        final String sql = "<script>insert into %s %s values %s on conflict (id)  do update set %s </script>";        final String tableName = tableInfo.getTableName();        final String filedSql = prepareFieldSql(tableInfo);        final String modelValuesSql = prepareModelValuesSql(tableInfo);        final String duplicateKeySql = prepareDuplicateKeySql(tableInfo);        final String sqlResult = String.format(sql, tableName, filedSql, modelValuesSql, duplicateKeySql);        logger.info("sql=={}",sqlResult);        return languageDriver.createSqlSource(configuration, sqlResult, modelClass);    }      @Override    protected String prepareInsertOrUpdateBathName() {        return "pgInsertOrUpdateBatch";    }      private String prepareDuplicateKeySql(TableInfo tableInfo) {        final StringBuilder duplicateKeySql = new StringBuilder();        if (!StringUtils.isEmpty(tableInfo.getKeyColumn())) {            duplicateKeySql.append(tableInfo.getKeyColumn()).append("=excluded.").append(tableInfo.getKeyColumn()).append(",");        }         tableInfo.getFieldList().forEach(x -> {            duplicateKeySql.append(x.getColumn())                    .append("=excluded.")                    .append(x.getColumn())                    .append(",");        });        duplicateKeySql.delete(duplicateKeySql.length() - 1, duplicateKeySql.length());        return duplicateKeySql.toString();    }     private String prepareModelValuesSql(TableInfo tableInfo) {        final StringBuilder valueSql = new StringBuilder();        valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");        if (!StringUtils.isEmpty(tableInfo.getKeyProperty())) {            valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");        }        tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));        valueSql.delete(valueSql.length() - 1, valueSql.length());        valueSql.append("</foreach>");        return valueSql.toString();    }         private String prepareFieldSql(TableInfo tableInfo) {        StringBuilder fieldSql = new StringBuilder();        if (!StringUtils.isEmpty(tableInfo.getKeyProperty())) {            fieldSql.append(tableInfo.getKeyColumn()).append(",");        }         tableInfo.getFieldList().forEach(x -> {            fieldSql.append(x.getColumn()).append(",");        });        fieldSql.delete(fieldSql.length() - 1, fieldSql.length());        fieldSql.insert(0, "(");        fieldSql.append(")");        return fieldSql.toString();    }}

 到此定义结束,下面开始使用

@Servicepublic class TNewExerciseServiceImpl extends ServiceImpl<TNewExerciseMapper, TNewExercise>        implements TNewExerciseService {    Logger logger = LoggerFactory.getLogger(getClass());//引入mapper @AutowiredTScoreMapper scoreMapper;//这样就可以批量新增更新操作了public void test(List<TScore> collect){ scoreMapper.pgInsertOrUpdateBatch(collect);} }

但是如果collect数据量太大会出现异常
“Tried to send an out-of-range integer as a 2-byte value: 87923”
是因为pg对于sql语句的参数数量是有限制的,最大为32767。

看pg源码

public void sendInteger2(int val) throws IOException {        if (val >= -32768 && val <= 32767) {            this.int2Buf[0] = (byte)(val >>> 8);            this.int2Buf[1] = (byte)val;            this.pGoutput.write(this.int2Buf);        } else {            throw new IOException("Tried to send an out-of-range integer as a 2-byte value: " + val);        }    }

从源代码中可以看到pgsql使用2个字节的integer,故其取值范围为[-32768, 32767]。

这意味着sql语句的参数数量,即行数*列数之积必须小于等于32767.

比如,总共有17个字段,因为最大是32767,这样最多允许32767/ 17 大约是1 927个,所以要分批操作,或有能力的童鞋可以自己修改pg的驱动呦

分批插入代码如下:

        public void detachSaveOrUpdate_score(List<TScore> list, int fieldCount) {        int numberBatch = 32767; //每一次插入的最大数        //每一次插入的最大行数 , 向下取整        int v = ((Double) Math.floor(numberBatch / (fieldCount * 1.0))).intValue();        double number = list.size() * 1.0 / v;        int n = ((Double) Math.ceil(number)).intValue(); //向上取整        for (int i = 0; i < n; i++) {            int end = v * (i + 1);            if (end > list.size()) {                end = list.size(); //如果end不能超过最大索引值            }            scoreMapper.pgInsertOrUpdateBatch(list.subList(v * i, end)); //插入数据库            logger.info("更新一次~~~{}-{}", v * i, end);        }    }

感谢各位的阅读,以上就是“mybatisplus批量更新太慢该怎么解决”的内容了,经过本文的学习后,相信大家对mybatisplus批量更新太慢该怎么解决这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: mybatisplus批量更新太慢该怎么解决

本文链接: https://www.lsjlt.com/news/350731.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • mybatisplus批量更新太慢该怎么解决
    这篇文章主要讲解了“mybatisplus批量更新太慢该怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mybatisplus批量更新太慢该怎么解决”吧!最近使用mybatis-plu...
    99+
    2023-07-05
  • mybatis-plus批量更新太慢该如何解决详解
    最近使用mybatis-plus的 saveOrUpdateBath 和saveBath接口执行特别慢,数据量大时往往需要十几分钟,打开日志查看原来批量操作也是循环单条数据插入的,那...
    99+
    2023-03-06
    mybatisplus 批量更新 mybatis-plus 批量更新 mybatis批量更新写法
  • mongodb批量更新数据慢怎么解决
    在 MongoDB 中进行批量更新数据时可能会遇到性能问题,以下是一些解决方法: 使用批量更新操作符:MongoDB 提供了批量...
    99+
    2024-04-09
    mongodb
  • mybatis-plus的批量新增/批量更新问题怎么解决
    本文小编为大家详细介绍“mybatis-plus的批量新增/批量更新问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“mybatis-plus的批量新增/批量更新问题怎么解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一...
    99+
    2023-07-06
  • pycharm更新索引太慢怎么办
    如果PyCharm的索引更新速度太慢,可以尝试以下几种方法来改善:1. 调整索引更新频率:在PyCharm的设置中找到“Editor...
    99+
    2023-09-15
    pycharm
  • win10更新慢怎么解决
    这篇文章主要介绍“win10更新慢怎么解决”,在日常操作中,相信很多人在win10更新慢怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”win10更新慢怎么解决”的疑惑有所帮助!接下来,请跟着小编一起来...
    99+
    2023-07-01
  • oracle批量insert很慢怎么解决
    在Oracle中批量插入数据时,速度较慢可能是由于以下几个原因造成的: 缓冲区大小不足:可以尝试调整数据库的缓冲区大小来提高插入数...
    99+
    2024-04-09
    oracle
  • oracle批量更新数据报错怎么解决
    当Oracle数据库在批量更新数据时报错,可能是由于以下原因导致的: 数据完整性约束:更新的数据违反了数据库表的完整性约束,如唯...
    99+
    2024-03-04
    oracle
  • mybatis和mybatisplus批量插入问题怎么解决
    这篇文章主要介绍了mybatis和mybatisplus批量插入问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇mybatis和mybatisplus批量插入问题怎么解决文章都会有所收获,下面我们一起...
    99+
    2023-07-06
  • 怎么解决pure-ftpdwho太慢或者登录太慢
    这篇文章主要介绍了怎么解决pure-ftpdwho太慢或者登录太慢,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。有时,pure-ftpwho显示结果很慢。有时侯当用户登录时,...
    99+
    2023-06-16
  • mybatisPlus更新字段值为null怎么解决
    这篇文章主要介绍“mybatisPlus更新字段值为null怎么解决”,在日常操作中,相信很多人在mybatisPlus更新字段值为null怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”mybatis...
    99+
    2023-07-06
  • mybatis执行update批量更新时报错怎么解决
    今天小编给大家分享一下mybatis执行update批量更新时报错怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一...
    99+
    2023-06-29
  • sql批量更新多条数据报错怎么解决
    当 SQL 批量更新多条数据报错时,可以尝试以下几种方法来解决问题: 检查 SQL 语句是否正确:首先检查 SQL 语句是否有语...
    99+
    2024-04-08
    sql
  • 如何解决Hibernate批量更新问题
    这篇文章主要介绍了如何解决Hibernate批量更新问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。对于Hibernate批量更新操作,Hibernate是将符合要求的数据...
    99+
    2023-06-17
  • VUE-CLI脚手架热更新太慢怎么办
    小编给大家分享一下VUE-CLI脚手架热更新太慢怎么办,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!用vue-cli构建了项目之...
    99+
    2024-04-02
  • SQLServer怎么实现批量更新
    这篇文章主要讲解了“SQLServer怎么实现批量更新”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SQLServer怎么实现批量更新”吧!1、直接用top...
    99+
    2024-04-02
  • mongodb怎么批量更新数据
    MongoDB提供了updateMany()方法来实现批量更新数据。 updateMany()方法的语法如下: db.collect...
    99+
    2023-10-26
    mongodb
  • mybatis怎么批量更新数据
    MyBatis 可以通过批量操作来更新数据。下面是一个示例代码,展示如何使用 MyBatis 进行批量更新数据:1. 首先,需要在 Mapper XML 文件中定义一个批量更新的 SQL 语句,如下所示:```xmlUPDATE tab...
    99+
    2023-08-09
    mybatis
  • Mybatis-plus 批量插入太慢的问题解决(提升插入性能)
    MyBatis-Plus(简称MP)是一个MyBatis的增强工具,旨在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。 特点 无侵入:只做增强不做改变,引入它不会...
    99+
    2024-04-02
  • win10更新后网速变慢怎么解决
    本文小编为大家详细介绍“win10更新后网速变慢怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“win10更新后网速变慢怎么解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。win10系统更新后网速变慢解...
    99+
    2023-06-28
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作