MyBatis批量插入数据
2017-08-23 本文已影响928人
8813d76fee36
项目很可能会遇到一次性插入多条数据的情况,虽然用循环逐条插入的方法也可以达到最终目的,但由于每插入一条数据就会提交一次事务,在数据量大的时候将会拖累性能。
本文中MyBatis使用是基于注解配置的,其实和XML的效果一样,只是用注解的Java配置方式替代了XML(虽然XML还是主流,但消除XML比较Spring Style~,大家可以尝试)。
准备工作
首先我们复习一下Oracle和MySQL批量插入数据的SQL语法。
- Oracle
INSERT INTO table_name (column1,column2,column3,...,column)
SELECT ?,?,?...? FROM DUAL UNION
SELECT ?,?,?...? FROM DUAL UNION
...
SELECT ?,?,?...? FROM DUAL
- MySQL
INSERT INTO table_name (column1,column2,column3,...,column)
VALUES
(?,?,?...?),
(?,?,?...?),
...
(?,?,?...?)
实现
看过两个数据库批量插入数据的SQL语句后,那么我们需要做的工作目标就很明确了,那就是需要动态的拼接出上面的SQL语句。
以批量插入用户数据为例:
/**用户类*/
public class User {
/**用户姓名*/
private String name;
/**用户年龄*/
private Integer age;
// getter/setter
}
/**Mapper接口*/
@Repository
public interface UserMapper {
@InsertProvider(type = UserSqlProvider.class, method = "inertUsers")
void inertUsers(@Param("userList") List<User> userList);
}
ORACLE
/**SQL构造类 ORACLE*/
public class UserSqlProvider {
public String inertUsers(Map<String, Object> map) {
//由Mapper传入的List在SQL构造类中将会包装在一个Map里,所以这里的参数是Map
//key就是Mapper中@Param注解配置的名称
List<User> userList = (List<User>) map.get("userList");
//构造SQL
StringBuilder sb = new StringBuilder();
sb.append("INSERT INTO USER ");
sb.append("(USER_NAME,USER_AGE) ");
//构造SQL模板
MessageFormat mf = new MessageFormat("SELECT #'{'userList[0].name, jdbcType=VARCHAR},#'{'userList[0].age, jdbcType=INTEGER}");
for (int i = 0; i < userList.size(); i ++) {
sb.append(mf.format(new Object[]{i}));
if (i < userList.size() - 1) {
sb.append("UNION ");
}
}
return sb.toString();
}
}
MySQL
/**SQL构造类*/
public class UserSqlProvider {
public String inertUsers(Map<String, Object> map) {
//由Mapper传入的List在SQL构造类中将会包装在一个Map里,所以这里的参数是Map
//key就是Mapper中@Param注解配置的名称
List<User> userList = (List<User>) map.get("userList");
//构造SQL
StringBuilder sb = new StringBuilder();
sb.append("INSERT INTO USER ");
sb.append("(USER_NAME,USER_AGE) ");
sb.append("VALUES ");
//构造SQL模板
MessageFormat mf = new MessageFormat("(#'{'userList[0].name, jdbcType=VARCHAR},#'{'userList[0].age, jdbcType=INTEGER})");
for (int i = 0; i < userList.size(); i ++) {
sb.append(mf.format(new Object[]{i}));
if (i < userList.size() - 1) {
sb.append(", ");
}
}
return sb.toString();
}
}
注意Mapper到Provider参数类型的变化(List --> Map),Mapper中传入的List会被包裹在一个Map中传给Provider,而key就是在Mapper的@Param注解中指定的名称(默认为list)。在Provider方法中使用List<T> list = (List<T>) map.get(key);即可拿到我们传入的List。
在return之前打断点看看构造出来的SQL是否符合在“准备工作”环节提到的格式,当格式匹配时数据即可成功插入,一次提交多条数据。