MyBatis实现批量插入方法实例

目录
  • 一、SQL实现示例
  • 二、Mybatis通过Mapper.xml文件实现
  • 三、在Mapper接口上使用注解
  • 四、限制一次批量插入数据的数量
  • 总结

一、SQL实现示例

假设我们只插入一条数据的时候,SQL如下

insert into table ([列名],[列名])  values ([列值],[列值]));
# 或者
insert into table values ([列值],[列值]))

当插入多条数据的时候,也就是需要批量插入的时候,SQL如下

insert into table ([列名],[列名])
VALUES
([列值],[列值])),
([列值],[列值])),
([列值],[列值]));

批量的用处:一次插入多条数据,这样就可以降低与数据库的IO次数,减少性能的损耗。

二、Mybatis通过Mapper.xml文件实现

比如这里的抽象的SQL就是

 insert into table (ID, PHONE,MESSAGE,APP_CODE,AREA_CODE,SEND_TYPE,SEND_TIME,CREATE_DATE,REMARK,serial_number)
 values
 (?,?,?,?,?,?,?,?,?,?,?,), (?,?,?,?,?,?,?,?,?,?,?,), (?,?,?,?,?,?,?,?,?,?,?,)

具体实现

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.scoreone.ap.mapper.MtTaskMapper">
<!--批量插入-->
	<insert id="insertList" parameterType="java.util.List">
		insert into ap_mt_task (ID, PHONE, MESSAGE,
		APP_CODE, AREA_CODE, SEND_TYPE,
		SEND_TIME, CREATE_DATE, REMARK,serial_number
		)
		VALUES
		<foreach collection="list" index="index" item="item" separator="," >
			(#{item.ID},#{item.PHONE},#{item.MESSAGE},#{item.APP_CODE},#{item.AREA_CODE},
			#{item.SEND_TYPE},#{item.SEND_TIME},#{item.CREATE_DATE},#{item.REMARK},#{item.serial_number})
		</foreach>
	</insert>
</mapper>

也可以不用在value里用foreach ,在整个SQL语句外面用。

参数解释

foreach的主要作用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有 collection,item,separator,index,open,close。

collection:指定要遍历的集合。表示传入过来的参数的数据类型。该属性是必须指定的,要做 foreach 的对象。在使用foreach的时候最关键的也是最容易出错的就是collection属性。在不同情况 下,该属性的值是不一样的,主要有一下3种情况:

  • a. 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
  • b. 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
  • c. 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map。Map 对象没有默认的键

item:表示集合中每一个元素进行迭代时的别名。将当前遍历出的元素赋值给指定的变量,然后用#{变量名},就能取出变量的值,也就是当前遍历出的元素。

separator:表示在每次进行迭代之间以什么符号作为分隔符。select * from tab where id in(1,2,3)相当于1,2,3之间的","

index:索引。index指定一个名字,用于表示在迭代过程中,每次迭代到的位置。遍历list的时候index就是索引,遍历map的时候index表示的就是map的key,item就是map的值。

open:表示该语句以什么开始,close表示以什么结束。

三、在Mapper接口上使用注解

举例

@Insert(“insert into blog(blogId,title,author) values(#blogId,#title,#author)”)
public boolean saveBlog(Blog blog);

这种对于简单的SQL可以使用法,对于复杂的SQL可读性太差(会有以大堆拼接符号),不建议使用。

xml、注解两种方式的区别:

foreach相当语句逐条INSERT语句执行,将出现如下问题:

(1)mapper接口的insert方法返回值将是最后一条INSERT语句的操作成功的记录数目(就是0或1),而不是所有INSERT语句的操作成功的总记录数目;

(2)当其中一条不成功时,不会进行整体回滚。

注解方式:当有一条插入不成功时,会整体回滚。

四、限制一次批量插入数据的数量

假设我们传过来的List一次有 10000 条,但是我们数据库批量插入不可能一下子插入 10000 条,我们就需要将这一批的数据进行限制,也就是再分成一小批一小批进行插入,比如下面,一次限制插入 15 条数据。

//举例这里就是进行 task表 的批量插入,限制一次 15 条
public int insertList(ArrayList<MtTask> taskList) {
//批量插入的时候,限制一批插入 15 条,效率会高一点,防止造成堆内存溢出异常
        if (taskList.size() > 0) {
            int InsertSize = 15;//一次插入15条
            //分成limit次发请求到数据库
            //这个算法就是防止不是在整除的时候少了一次,比如 32 个需要插四次
            int limit = (taskList.size() + InsertSize - 1) / InsertSize;//需要插入多少次

            //这个流的意思就是,进行 limit 次,每一次插入15个

            //根据起始值seed(0),每次生成一个指定递增值(n+1)的数,limit(limit)用于截断流的长度,也就是进行limit次的里面的操作
            Stream.iterate(0, n -> n + 1).limit(limit).forEach(a -> {
                // skip就是跳过前面(a * InsertSize)条数据,因为 a是从0开始,到limit,skip(0)的时候是空的不插入
                // .limit(InsertSize)->限制每次插入数据的15条  .collect(Collectors.toList()->组成一个toList
                List<MtTask> mtTaskList = taskList.stream().skip(a * InsertSize).limit(InsertSize).collect(Collectors.toList());
                //doSomething();
                mtTaskMapper.insertList(mtTaskList);
            });
}

上面这是使用流的,下面是不用使用流的

/*不用流的方法*/
            //集合的大小
            int size = taskList.size();
            //需要拆分成的每个集合大小
            int newSize = 15;
            //需要需要拆分成的小集合数量(拆分没有余数则取相除的结果,如果有余数则需要再加一个集合存放余数)
            //这个就是直接判断出了之后有没有余数,有就多加一次,没有就整除刚好
            int sum = size % newSize != 0 ? (size / newSize) + 1 : size / newSize;
            //循环参照大集合,能拆分成的集合有多少个就循环多少遍
            for (int i = 0; i < sum; i++) {
                //如果当前下标+1 等于拆分成的集合数量,则说明这是最后一组(也可能仅能拆成一个集合 下标0 + 1 == 集合数量 1)
                if ((i + 1) == sum) {
                    //截取的下标开始位
                    int startIndex = (i * newSize);
                    //截取的结束下标位置
                    int endIndex = size;
                    //插入
                    result = mtTaskMapper.insertList(taskList.subList(startIndex, endIndex));
                } else {
                    //截取的下标开始位
                    int startIndex = (i * newSize);
                    //截取的结束下标位置
                    int endIndex = (i + 1) * newSize;
                    result = mtTaskMapper.insertList(taskList.subList(startIndex, endIndex));
                }
            }

=还有一种就是达到我们限制的数量就插入

@Override
public int insertList(ArrayList<MtTask> taskList) {

if(!CollectionUtils.isEmpty(taskList)){
            List<MtTask> subList = new ArrayList<>();
            int num = 0;
            for (MtTask mtTask : taskList ){
                subList.add(mtTask);
                num ++ ;
                if(num >= 500){
                    mtTaskMapper.insertList(subList);
                    subList.clear();
                    subList = new ArrayList<>();
                }
            }
            if(num > 0){
                mtTaskMapper.insertList(subList);
                subList.clear();
            }
        }
}

总结

到此这篇关于MyBatis实现批量插入的文章就介绍到这了,更多相关MyBatis批量插入内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • mybatis中批量插入的两种方式(高效插入)

    MyBatis简介 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录. 一.mybiats foreach标签 foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合.foreach元素的属性主

  • Mybatis三种批量插入数据的方式

    1. 循环插入 mapper.xml: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.buhe.

  • MyBatis批量插入大量数据(1w以上)

    问题背景:只用MyBatis中foreach进行批量插入数据,一次性插入超过一千条的时候MyBatis开始报错.项目使用技术:SpringBoot.MyBatis 批量插入碰到的问题: java.lang.StackOverflowError: null 该问题是由于一次性插入数据1w条引起的,具体插入代码如下: userDao.batchInsert(list); <insert id="batchInsert" parameterType="java.util.Li

  • 详解MyBatis直接执行SQL查询及数据批量插入

    一.直接执行SQL查询: 1.mappers文件节选 <resultMap id="AcModelResultMap" type="com.izumi.InstanceModel"> <result column="instanceid" property="instanceID" jdbcType="VARCHAR" /> <result column="insta

  • Mybatis批量插入并返回主键id的方法

    目录 场景 错误 分析原因 排查问题 场景 在做商城的时候,sku表进行了拆分,sku的基本信息以及sku的库存表.因为库存会经常的变动,会导致行锁. 这里就是新增的时候,因为在新增商品的时候,会有多条sku的数据进行批量的插入,那么有批量插入sku基本信息以及批量插入sku的库存信息. 其中,就需要批量插入sku的基本信息的时候,返回主键id,这就能够在sku批量插入库存信息的时候能够插入skuId: 错误 nested exception is org.apache.ibatis.execu

  • MyBatis批量插入数据的三种方法实例

    目录 前言 准备工作 1.循环单次插入 2.MP 批量插入 ① 控制器实现 ② 业务逻辑层实现 ③ 数据持久层实现 MP 性能测试 MP 源码分析 3.原生批量插入 ① 业务逻辑层扩展 ② 数据持久层扩展 ③ 添加 UserMapper.xml 原生批量插入性能测试 缺点分析 解决方案 总结 前言 批量插入功能是我们日常工作中比较常见的业务功能之一,之前我也写过一篇关于<MyBatis Plus 批量数据插入功能,yyds!>的文章,但评论区的反馈不是很好,主要有两个问题:第一,对 MyBat

  • MyBatis批量插入(insert)数据操作

    在程序中封装了一个List集合对象,然后需要把该集合中的实体插入到数据库中,由于项目使用了Spring+MyBatis的配置,所以打算使用MyBatis批量插入,由于之前没用过批量插入,在网上找了一些资料后最终实现了,把详细过程贴出来. 实体类TrainRecord结构如下: public class TrainRecord implements Serializable { private static final long serialVersionUID = -12069604621179

  • MyBatis实现批量插入方法实例

    目录 一.SQL实现示例 二.Mybatis通过Mapper.xml文件实现 三.在Mapper接口上使用注解 四.限制一次批量插入数据的数量 总结 一.SQL实现示例 假设我们只插入一条数据的时候,SQL如下 insert into table ([列名],[列名]) values ([列值],[列值])); # 或者 insert into table values ([列值],[列值])) 当插入多条数据的时候,也就是需要批量插入的时候,SQL如下 insert into table ([

  • Oracle + Mybatis实现批量插入、更新和删除示例代码

    前言 Mybatis是web工程开发中非常常用的数据持久化的框架,通过该框架,我们非常容易的进行数据库的增删改查.数据库连接进行事务提交的时候,需要耗费的资源比较多,如果需要插入更新的数据比较多,而且每次事务只提交一条数据,会造成非常大的数据库资源浪费,导致数据库性能.系统性能大幅度下降. 关于mybatis的批量插入,网上的多数示例多半是关于MySQL数据库的,关于Oracle数据库的例子比较少.本文将给大家介绍关于Oracle+Mybatis批量插入.更新和删除的相关内容,下面话不多说了,来

  • mybatis foreach批量插入数据:Oracle与MySQL区别介绍

    下面给大家介绍mybatis foreach批量插入数据:Oracle与MySQL不同点: •主要不同点在于foreach标签内separator属性的设置问题: •separator设置为","分割时,最终拼接的代码形式为:insert into table_name (a,b,c) values (v1,v2,v3) ,(v4,v5,v6) ,... •separator设置为"union all"分割时,最终拼接的代码形式为:insert into table

  • mysql 循环批量插入的实例代码详解

    背景 前几天在MySql上做分页时,看到有博文说使用 limit 0,10 方式分页会有丢数据问题,有人又说不会,于是想自己测试一下.测试时没有数据,便安装了一个MySql,建了张表,在建了个while循环批量插入10W条测试数据的时候,执行时间之长无法忍受,便查资料找批量插入优化方法,这里做个笔记. 数据结构 寻思着分页时标准列分主键列.索引列.普通列3种场景,所以,测试表需要包含这3种场景,建表语法如下: drop table if exists `test`.`t_model`; Crea

  • pymongo insert_many 批量插入的实例

    我就废话不多说了,大家还是直接看代码吧~ lt=client.fangjia.district_stat_all_0416 dl = dt.find(query) bf=[] for m in dl: bf.append(m) if len(bf)==20000: lt.insert_many(bf) bf=[] lt.insert_many(bf) 补充知识:Python操作Mongodb插入数据的两种方法:insert_one()与insert_many() 代码说明: 将mysql中tab

  • 浅谈MyBatis原生批量插入的坑与解决方案

    目录 原生批量插入的"坑" 解决方案 分片 Demo 实战 原生批量插入分片实现 总结 前面的文章咱们讲了 MyBatis 批量插入的 3 种方法:循环单次插入.MyBatis Plus 批量插入.MyBatis 原生批量插入,详情请点击<MyBatis 批量插入数据的 3 种方法!> 但之前的文章也有不完美之处,原因在于:使用 「循环单次插入」的性能太低,使用「MyBatis Plus 批量插入」性能还行,但要额外的引入 MyBatis Plus 框架,使用「MyBati

  • php往mysql中批量插入数据实例教程

    前言 假如说我有这样一个表,我想往这个表里面插入大量数据 CREATE TABLE IF NOT EXISTS `user_info` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键', `name` varchar(255) NOT NULL default '' COMMENT '姓名', `age` int(11) NOT NULL default '0' COMMENT '年龄', PRIMARY KEY (`id`) ) ENG

  • spring中使用mybatis实现批量插入的示例代码

    有3种实现方式:foreach,spring事务,以及ExecutorType.BATCH. 1. foreach方式 这种方式实际是对SQL语句进行拼接,生成一个长长的SQL,对很多变量进行绑定.如果数据量不大(1000个以内),可以用这种方式.如果数据量太大,可能数据库会报错. 定义接口 public interface StudentMapper05 { public void insertStudent(List<Student> studentList); } 定义mapper 适用

  • mybatis实现批量插入并返回主键(xml和注解两种方法)

    目录 mybatis批量插入并返回主键(xml和注解两种方法) mybatis批量插入 xml形式 注解形式 mybatis批量插入并返回主键笔记 mapper中的代码 xml中的代码,collection必须填list类型 mybatis批量插入并返回主键(xml和注解两种方法) mybatis批量插入 在mysql数据库中支持批量插入,所以只要配置useGeneratedKeys和keyProperty就可以批量插入并返回主键了. 比如有个表camera,里面有cameraNo,chanIn

随机推荐