batch应用注意点

有人说MySql的JDBC驱动,不是真正支持批量操作的,就算你在代码中调用了批量操作的方法,MySql的JDBC驱动也是按照一般操作来处理的。

但其实并非如此,Mysql 是有特殊的方式优化整个batch insert 结果的。

可不可以先假设 batch 的方式与非batch一样,每一条insrt语句事实上均是单独发往服务器的呢?

浏览下源代码吧。

好多兄弟都描述了源代码,直接从那几个类入手吧,事实上关键的类是这个 com.mysql.jdbc.PreparedStatement

先看了其中的 addBatch 方法,没有任何问题,只是将语句添加进入一个 List 中保存。

那么 executeBatch 呢?

再贴一下吧, 关键看其中的这部分,顺带说一下, 这个mysql-jdbcdriver的源代码是 5.1.13的

  1. try {
  2. clearWarnings();
  3. if (!this.batchHasPlainStatements
  4. && this.connection.getRewriteBatchedStatements()) {
  5. if (canRewriteAsMultiValueInsertAtSqlLevel()) {
  6. return executeBatchedInserts(batchTimeout); //执行路径之一
  7. }
  8. if (this.connection.versionMeetsMinimum(4, 1, 0)
  9. && !this.batchHasPlainStatements
  10. && this.batchedArgs != null
  11. && this.batchedArgs.size() > 3/* cost of option setting rt-wise */) {
  12. return executePreparedBatchAsMultiStatement(batchTimeout); //执行路径之二
  13. }
  14. }
  15. return executeBatchSerially(batchTimeout); //执行路径之三
  16. } finally {
  17. clearBatch();
  18. }
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();   
} 


其实最终,executeBatch 的执行路径有三种可能。代码中我已标出来


代码不算太复杂,但是有一个参数能帮助我们更快的确定mysql的batch工作机制,那就是
mysql jdbc driver 的connection url, 其中有一个参数是: rewriteBatchedStatements


完整的参数参考看这里:http://ftp.ntu.edu.tw/ftp/pub/MySQL/doc/refman/5.1/en/connector-j-reference-configuration-properties.html

rewriteBatchedStatements 参数默认为false, 需要手工设置为true,设置方式大概像这样:

  1. String connectionUrl="jdbc:mysql://192.168.1.100:3306/test?rewriteBatchedStatements=true";
String connectionUrl="jdbc:mysql://192.168.1.100:3306/test?rewriteBatchedStatements=true";    


默认时候,rewriteBatchedStatements=false时,执行路径会跳到 executeBatchSerially,此方法内部将语句一条条发送,与非batch处理简直一样,所以慢,就在这里了。

当设为 true时,会执行executeBatchedInserts方法,事实上mysql支持这样的插入语句

  1. insertinto t_user(id,uname) values(1, '1'), (2,'2'), (3, '3') ....
insert into t_user(id,uname) values(1, '1'), (2,'2'), (3, '3') ....  


针对rewriteBatchedStatements=true 参数我做了测试,我加了这个参数,做同们的插入10万条记录测试:
我的mysql 安装的虚拟机上,所以慢一些。

MySql JDBC 驱动版本 结果
5.0.8 没有提高 18秒
5.1.7 没有提高 18秒
5.1.13 有提高 1.6秒

所以Mysql的批量操作一定要加上MySql连接的url中要加rewriteBatchedStatements参数设为true

http://blog.csdn.net/miclung/article/details/7231780

猜你喜欢

转载自lf6627926.iteye.com/blog/1848688