假如需要搬一万块砖到楼顶,有一部电梯,电梯一次可以放适量的砖(最多放 500)。可以选择一次运送一块砖,也可以一次运送 500 块砖,哪个时间消耗大?
一、sql 层面实现数据插入
- 单条插入数据的写法:
insert into table ([列名],[列名]) values ([列值],[列值]));
或:
insert into table values ([列值],[列值]));
- 批量插入
一种可以在代码中循环执行上面的语句,但是这种效率太差。另一种,可以用 MySQL 支持的批量插入语句,这种方式更高效。
insert into table ([列名],[列名])
VALUES
([列值],[列值]),
([列值],[列值]),
([列值],[列值]);
批量的好处:可以避免程序和数据库建立多次连接,增加服务器负荷。
二、MyBatis 层面批量插入数据到数据库
两种方式:xml 文件和注解。使用批量插入执行的 sql 语句应该等价于:
insert into table (id, name,sex,address)
values
(?,?,?,?),(?,?,?,?),(?,?,?,?),(?,?,?,?)
1️⃣xml 配置
最基础的是用 mapping.xml 配置的方式,包括以下两种具体方式:
- mapping.xml 中 insert 语句可以写成单条插入,在调用方循环 1000 次
insert into person (id, name,sex,address)
values
(#{id,jdbcType=INTEGER},#{name,jdbcType=VARCHAR},
#{sex,jdbcType=VARCHAR},#{address,jdbcType=VARCHAR})
- mapping.xml 中 insert 语句写成一次性插入一个 1000 的 list
insert into person ( )
values
(null,#{item.name},#{item.sex},#{item.address})
参数解释:
foreach 的主要作用在构建 in 条件中,它可以在 sql 语句中进行迭代一个集合。foreach 元素的属性主要有 collection,item,separator,index,open,close。
collection:指定要遍历的集合。表示传入过来的参数的数据类型。该属性是必须指定的,要做 foreach 的对象。在使用 foreach 的时候最关键的也是最容易出错的就是 collection 属性。在不同情况 下,该属性的值是不一样的,主要有一下 3 种情况:
a. 如果传入的是单参数且参数类型是一个 List 的时候,collection 属性值为 list。
b. 如果传入的是单参数且参数类型是一个数组的时候,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 接口中的使用:
public interface TabMapper {
public List getTabsByConditionLike(@Param("list")List ids);
}
2️⃣注解
MyBatis 提供用于插入数据的注解有两个:@insert,@InsertProvider。类似还有:@DeleteProvider、@UpdateProvider和@SelectProvider。
作用:
用来在实体类的 Mapper 类里注解保存方法的 sql 语句。
区别:
@Insert 是直接配置 sql 语句,而 @InsertProvider 则是通过 sql 工厂类及对应的方法生产 sql 语句,这种方法的好处在于,可以根据不同的需求生产出不同的 sql,适用性更好。
使用:
@Insert("insert into blog(blogId,title,author) values(#blogId,#title,#author)")
public boolean saveBlog(Blog blog);
@InsertProvider
在 mapper 接口中的方法上使用 @InsertProvider 注解:
参数解释:
type 为工厂类的类对象,
method 为对应的工厂类中的方法,方法中的 @Param(“list”) 是因为批量插入传入的是一个 list,但是 Mybatis 会将其包装成一个 map。其中 map 的 key 为“list”,value为传入的 list。
三、xml/注解 两种方式的区别
1️⃣foreach 相当语句逐条 insert 语句执行,将出现如下问题:
- mapper 接口的 insert 方法返回值将是最后一条 insert 语句的操作成功的记录数目(就是0或1),而不是所有 insert 语句的操作成功的总记录数目;
- 当其中一条不成功时,不会进行整体回滚。
2️⃣注解方式:当有一条插入不成功时,会整体回滚。