Java学习开发随笔

MyBatis批量插入数据

2017-08-23  本文已影响928人  8813d76fee36

项目很可能会遇到一次性插入多条数据的情况,虽然用循环逐条插入的方法也可以达到最终目的,但由于每插入一条数据就会提交一次事务,在数据量大的时候将会拖累性能。
本文中MyBatis使用是基于注解配置的,其实和XML的效果一样,只是用注解的Java配置方式替代了XML(虽然XML还是主流,但消除XML比较Spring Style~,大家可以尝试)。

准备工作

首先我们复习一下Oracle和MySQL批量插入数据的SQL语法。

INSERT INTO table_name (column1,column2,column3,...,column)
SELECT ?,?,?...? FROM DUAL UNION
SELECT ?,?,?...? FROM DUAL UNION
...
SELECT ?,?,?...? FROM DUAL
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是否符合在“准备工作”环节提到的格式,当格式匹配时数据即可成功插入,一次提交多条数据。

上一篇 下一篇

猜你喜欢

热点阅读