在使用MyBatis数据框架时,难免会遇到需要批量操作的数据倒入或者删除,这事一般人可能会直接采用最原始的foreach之类的操作,那么有没有更加高效而且操作数据库少的方式呢,答案肯定是有的。

先上代码:

@InsertProvider(type = Provider.class, method = "batchInsert")
int batchInsert(@Param("list") List<TransCall> transCalls);

class Provider {
        /* 批量插入 */
        public String batchInsert(Map map) {
            List<TransCall> transList = (List<TransCall>) map.get("list");
            StringBuilder sb = new StringBuilder();
            sb.append("INSERT INTO trancall (transcallName,transcallNumber) VALUES ");
            MessageFormat mf = new MessageFormat("(#'{'list[{0}].transcallName}, #'{'list[{0}].transcallNumber})");
            for (int i = 0; i < transList.size(); i++) {
                sb.append(mf.format(new Object[]{String.valueOf(i)}));
                if (i < transList.size() - 1)
                    sb.append(",");
            }
            return sb.toString();
        }
 }

MyBatis会把batchInsert方法中的List类型的参数存入一个Map中, 默认的key是”list”, 可以用@Param注解自定义名称, MyBatis在调用@InsertProvide指定的方法时将此map作为参数传入, 所有代码中使用List transList = (List) map.get(“list”);获取list参数. 可以从代码中看出生成的SQL语句大致为:

INSERT INTO trancall (transcallName, transcallNumber) VALUES (null, #{list[0].transcallName},#{list[0].transcallNumber}), (null, #{list[1].transcallName},#{list[1].transcallNumber})[,(null, #{list[i].transcallName},#{list[i].transcallNumber})]

⚠️这里需要注意:网上很多通过MessageFormat进行拼接的时候,当批处理的大小size大于三位数的时候,出现异常。原因是3位数以上比如1000构建出的message为: 当size达到3位数以上时构建出的message为: (#{list[1,000].transcallName }) 正确的应该是:(#{list[1000].transcallName }) 所以修改:

mf.format(new Object[]{i})===改为=>mf.format(new Object[]{String.valueOf(i)})

效果:相对于foreach单条执行insert语句,该注解批处理是10倍的速度,毕竟只操作了一次数据库。