记MybatisPlus使用saveBatch注意事项

为了不重复写 mapper 文件里的foreach 标签,我们通常会将mybatis升级为mybatis-plus,从而使用Iservice

为了不重复写 mapper 文件里的foreach 标签,我们通常会将mybatis升级为mybatis-plus,从而使用Iservice里面的saveBatch方法;

一、foreach标签用法

 <select id="getUserInfo" resultType="com.test.UserList">
	SELECT
	*
	FROM user_info
	where
	<if test="userName!= null and userName.size() >0">
		USERNAME IN
		<foreach collection="userName" item="value" separator="," open="(" close=")">
			#{value}
		</foreach>
	</if>
</select>

二、saveBatch用法

集成serviceImpl:

public class ReportServiceImpl extends ServiceImpl<ReportDao,ReportPo> implements IReportService

调用this.saveBatch()方法:

 this.saveBatch(list);

三、出现的问题

在生产使用中经过实测发现这个savebatch方法比单个的insert效率还慢

源码:

try {  
    clearWarnings();  
  
    if (!this.batchHasPlainStatements  
            && this.connection.getRewriteBatchedStatements()) {  
          
          
        if (canRewriteAsMultiValueInsertAtSqlLevel()) {  
            return executeBatchedInserts(batchTimeout);
        }  
          
        if (this.connection.versionMeetsMinimum(4, 1, 0)   
                && !this.batchHasPlainStatements  
                && this.batchedArgs != null   
                && this.batchedArgs.size() > 3 /* cost of option setting rt-wise */) {  
            return executePreparedBatchAsMultiStatement(batchTimeout);
        }  
    }  
  
    return executeBatchSerially(batchTimeout); 
} finally {  
    clearBatch();  
}  

可以看出有一个参数能帮助我们更快的确定mysql的batch工作机制,那就是mysql jdbc driver 的connection url, 其中有一个参数是: rewriteBatchedStatements

rewriteBatchedStatements 参数默认为false, 需要手工设置为true,设置方式:

url:jdbc:mysql://192.168.1.100:3306/test?rewriteBatchedStatements=true

默认状态时rewriteBatchedStatements=false,执行路径会跳到 executeBatchSerially,此方法内部将语句一条条发送,与非batch处理简直一样,所以效率低;
当设为 true时,会执行executeBatchedInserts方法,事实上mysql支持这样的插入语句:insert into t_user(id,uname) values(1, '1'), (2,'2'), (3, '3') ...

四、总结

  • MySQL的JDBC连接的url中要加rewriteBatchedStatements参数,并保证5.1.13以上版本的驱动,才能实现高性能的批量插入。

  • MySQL JDBC驱动在默认情况下会无视executeBatch()语句,把我们期望批量执行的一组sql语句拆散,一条一条地发给MySQL数据库,批量插入实际上是单条插入,直接造成较低的性能。

  • 只有把rewriteBatchedStatements参数置为true, 驱动才会帮你批量执行SQL

  • 这个选项对INSERT/UPDATE/DELETE都有效

Comment