本篇来学习Mybatis如何批量插入数据,在此之前先介绍传统JDBC模式下如何进行数据的批量插入操作,因为Mybatis其本质上是封装了JDBC,因此了解JDBC模式下的数据批量插入有利于更好地理解和使用Mybatis。总的来说就三个内容:1、复习传统JDBC模式下数据的批量插入操作;2、Mybatis借助Mysql数据库对批量插入的支持;3、Mybatis基于SqlSession的ExecutorType进行批量添加。

传统JDBC模式下数据的批量插入操作

传统JDBC模式下数据的批量插入操作方法有两种:1、在Java代码中使用for循环直接插入SQL数据(如execute()/executeUpdate()方法);2、借助于statement、Prestatement对象的批处理方法addBatch。

两种操作缺点:传统JDBC模式下数据的批量插入操作缺点:1、在Java代码中使用for循环直接插入SQL数据这种方式效率严重低下,需要频繁获取Session连接;2、使用批处理操作会使得代码和SQL之间过度耦合,造成代码量过大现象。

Mybatis数据批量插入方法

Mybatis数据批量插入方法有两种:1、借助于foreach标签,使用insert into table values();;2、借助于Mysql数据库连接属性allowMultiQueries=true

其实这两种方法就是使用以下两种sql语句方式:第一种是insert into table values(),(),(),(),(),();;第二种则是insert into table values();insert into table values();insert into table values();insert into table values();,也就是后面增加很多数据或者多次执行数据。

新建一个Maven项目mybatis_insertdata(不使用模板,这个项目和mybatis_parameter项目几乎一致),具体的配置代码直接看git仓库,这里就只粘贴和业务相对紧密的代码。

借助于foreach标签实现数据批量插入

PersonMapper.java文件中新增addPersons方法:

1
2
//使用foreach标签实现数据批量插入
public int addPersons(@Param("persons")List<Person> personList);

PersonMapper.xml文件中新增代码如下:

1
2
3
4
5
6
7
    <!--使用foreach标签实现数据批量插入,注意由于使用了@Param注解,因此collection就是注解中的内容-->
<insert id="addPersons">
insert into person(username,email,gender) values
<foreach collection="persons" item="person" index="i" separator=",">
(#{person.username},#{person.email},#{person.gender})
</foreach>
</insert>

ParameterTest.java文件中新增insertDataByForeach方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    //借助于foreach标签实现数据的批量插入
@Test
public void insertDataByForeach(){
//SqlSessionFactory相当于数据库,SqlSession相当于一次连接
SqlSession sqlSession = getSqlSessionFactory().openSession();
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
List<Person> personList = new ArrayList<Person>();
for(int i=0;i<10;i++){
Person person = new Person();
person.setUsername("hello"+i);
person.setEmail("world"+i);
person.setGender("男");
personList.add(person);
}
personMapper.addPersons(personList);
sqlSession.commit();
}

运行结果如下:

使用Mysql数据库连接属性实现数据批量插入

首先在db.properties中添加allowMultiQueries=true

1
2
3
4
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis_parameter?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
jdbc.username=root
jdbc.password=root

接着在PersonMapper.java文件中新增addPersonsByBatch方法:

1
2
//使用foreach标签同时借助于Mysql数据库连接属性实现数据批量插入
public int addPersonsByBatch(@Param("personBatch")List<Person> personList);

PersonMapper.xml文件中新增代码如下(注意分割号是分号):

1
2
3
4
5
6
7
<!--使用foreach标签同时借助于Mysql数据库连接属性实现数据批量插入-->
<insert id="addPersonsByBatch">
<foreach collection="personBatch" item="person" index="i" separator=";">
insert into person(username,email,gender) values
(#{person.username},#{person.email},#{person.gender})
</foreach>
</insert>

ParameterTest.java文件中新增insertDataByForeachAndMysql方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//使用foreach标签同时借助于Mysql数据库连接属性实现数据批量插入
@Test
public void insertDataByForeachAndMysql(){
//SqlSessionFactory相当于数据库,SqlSession相当于一次连接
SqlSession sqlSession = getSqlSessionFactory().openSession();
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
List<Person> personList = new ArrayList<Person>();
for(int i=0;i<5;i++){
Person person = new Person();
person.setUsername("good"+i);
person.setEmail("day"+i);
person.setGender("女");
personList.add(person);
}
personMapper.addPersonsByBatch(personList);
sqlSession.commit();
}

运行代码发现正常,注意在db.properties文件中必须添加allowMultiQueries=true,否则程序运行会出错。

基于SqlSession的ExecutorType实现数据批量插入

基于SqlSession的ExecutorType实现数据批量插入,这种方式是Mybatis中真正处理批量插入数据的方式。前面介绍的两种方式:第一种是values和多个号;第二种是多个insert into;号。其实在数据库的底层实现来说,无论是逗号还是分号它们都会去拼接一个非常长的字符串,数据库引擎对于长字符串的解析能力较弱,因此在实际开发过程中不会采取拼接字符串的方式。

通常是这样操作的,在SqlSession sqlSession = getSqlSessionFactory().openSession(ExecutorType.BATCH);中会使用ExecutorType,而ExecutorType类型有BATCH/SIMPLE/REUSE三种方式,这里的使用批处理模式即可,仅仅这个不同其他的和插入单个数据的操作方式一样。

PersonMapper.java文件中新增addPerson方法:

1
2
//基于SqlSession的ExecutorType实现数据批量插入
int addPerson(Person person);

PersonMapper.xml文件中新增代码如下:

1
2
3
4
<!--基于SqlSession的ExecutorType实现数据批量插入-->
<insert id="addPerson" parameterType="Person">
insert into person(username,email,gender)values(#{username},#{email},#{gender})
</insert>

ParameterTest.java文件中新增insertDataByForeach方法:

1
2
3
4
5
6
7
8
9
10
11
12
  //    基于SqlSession的ExecutorType实现数据批量插入
@Test
public void insertDataByExecutorType() {
//SqlSessionFactory相当于数据库,SqlSession相当于一次连接(此处启用了Batch批处理模式)
//ExecutorType类型有BATCH/SIMPLE/REUSE三种方式
SqlSession sqlSession = getSqlSessionFactory().openSession(ExecutorType.BATCH);
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
for (int i =0;i<10000;i++){
personMapper.addPerson(new Person("envy","envy@qq.com","男"));
}
sqlSession.commit();
sqlSession.close();

执行该方法,发现数据被正常插入到数据库中。

简单总结一下:1、基于mysql时的数据插入时,选择第一种方式,即使用foreach标签进行遍历输出;2、可以使用Executor的Batch批量添加,它可与Spring框架进行整合。