`
skzr.org
  • 浏览: 355926 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

[转载]主题:MySql的JDBC驱动不支持批量操作(更新)

阅读更多

 

主题:MySql的JDBC驱动不支持批量操作(更新)

srdrm的回复非常好:)

 

mysql 虽然用得不多,公司一直用的mssql. 

楼主的测试结果让人非常失望... 

但mysql名气这么大,不太相信在这样的问题上会出现与oracle这么大的差距。 

直觉告诉我,应该是一些简单的设置问题,事实上最后得到的结果也是如此的。 

带着解决这个疑惑的想法,依据大家之前得到的一些结果,信息,开始测试 

工具: 
eclipse-3.6, mysql-5.1.48, mysql-jdbc-driver 5.1.11, mysql workbench 

前面说过了,我直觉认为代码不会有问题,所以先着手改善mysql 的服务器配置,innodb的设置。 
改了几个参数,都没有什么效果。加大了日志缓存,只是提高到7000多毫秒。最后甚至很多歪门邪道的设置都大胆用了,一度让mysql 无法启动。。。最终都收效甚微,这个步骤大概试了将近一个小时。 

这条路看来是走不通了。。得寻找别的方法 


冷静下来想想,其实从代码中应该是可以发现些端倪 
楼主的非batch代码中,每次调用 execute() 其实是会通过网络发送一条语句到服务器端的,是不会在客户端排队攒着的。 
因为这个方法必须返回一个结果。它必然跟服务器发生了一次交互。 

而在batch处理的代码中,其addBatch 就是无返回值,它提供了一个可能就是在客户端将语句缓存排队攒着,最后executeBatch时才发送到服务器端。

用代码可以证明,在batch处理方法的代码中,在 executeBatch, 及 commit 方法执行前,分别安插两条打印时间语句:

Java代码 
  1. System.out.println("before executeBatch. "+ (System.currentTimeMillis()-a)+" ms");  
  2. prest.executeBatch();  
  3. System.out.println("before commit. "+ (System.currentTimeMillis()-a)+" ms");  
  4. conn.commit();          



在我机器上的结果是,

Java代码 
  1. before executeBatch. 279 ms  
  2. before commit. 7922 ms  
  3. MySql批量插入10万条记录用时7923 ms  




说明客户端在攒语句时,相当的快,279毫秒就完成了,但在 executeBatch 这个方法的调用过程中,花费了 7920  减 去 279 的毫秒数。大部分都耗在这里了。 最后提交事务非常快,1毫秒而已 

想想看,前边说过,非batch和batch的处理几乎是一样的时间。 

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

浏览下源代码吧。 

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

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

那么 executeBatch 呢? 

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

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



其实最终,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,设置方式大概像这样:

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



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

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

Sql代码 
  1. insert into t_user(id,uname) values(1, '1'), (2,'2'), (3, '3') ....  



所以,当rewriteBatchedStatements=true时, 楼主的例子会被编译为以上形式,当然values里全是?, mysql 客户端会对这些值添加参数. 这样的方式当然就快很多了。 

其实到现在还不太了解 batch 处理时,执行计划这个概念,不过我猜 mysql 可能并没有缓存执行计划。而只是将这些语句组合起来了。 

所以如果是这样,他的机制与oracle可能是有所不同的,还不是达到最高效的机制,也许这就是开源与商业的区别吧。 

我们如果想更深入了解,只能借助于一些服务器端监视工具,sql分析工具了。 




写贴子过程断断续续给打扰了,本来还有一些可以写更详细的,就留给大家自己去探索了,包括,如果调用addBatch(String sql)后,则仍会按照 executeBatchSerially 方式执行,包括何时执行 executePreparedBatchAsMultiStatement,都可以继续深入了解。 

后记,当使用 update 时,会执行 executePreparedBatchAsMultiStatement,但是如果攒的语句太多,会导致 mysql 崩溃. 我的测试中10000条update不会有事,20000时,mysql 就崩掉了。

 

分享到:
评论

相关推荐

    mysql,jdbc详解,与ibatis对比。批量查询,分页处理。

    mysq增删改查,jdbc 驱动加载 各个类和接口详解,与ibatis对比。批量查询,分页处理。

    hibernate-batch-size-test:Hibernate hibernate.jdbc.batch_size 测试

    Hibernate hibernate.jdbc.batch_size 测试带有 MySQL JDBC 驱动程序的 Hibernate 批量插入示例。 에 관한 설명

    Sql2NoSql-Importer:将Sql数据(使用任何JDBC驱动程序)导入到NoSQL数据库

    将您的Sql数据(支持任何JDBC驱动程序,例如MySQL,Oracle,PostgreSQL)导入NoSQL数据库。 当前受支持: Mongodb , CouchDB和Elasticsearch 数据可以批量导入以减少处理时间,并且可以转发到多个Elasticsearch...

    数据库工具,把数据库表数据保存成文件

    把数据库表数据保存成文件的工具,可以导出文件,还可以导入。jdbc直连,批量提交。oracle,mysql。加驱动就可以支持其他的数据库。

    seddi:堆栈交换数据转储导入器

    支持任何具有JDBC驱动程序和Hibernate方言的数据库 灵活的配置允许自定义数据转储字段到数据库字段的映射 本机7z存档支持-直接从下载的存档导入,无需解压缩! 多线程支持 批量导入 ==状态== 大部分工作已经完成。...

    2021数据仓库服务常见问题汇总-华为-51页.pdf

    4.1 GaussDB(DWS) 是否支持第三方客户端以及JDBC 和ODBC 驱动程序? 4.2 是否支持使用Navicat 连接GaussDB(DWS)? 4.3 可以通过SSH 连接GaussDB(DWS) 集群的节点吗? 4.4 无法连接数据仓库集群时怎么处理? 4.5 为...

    疯狂JAVA讲义

    9.6.2 Java支持的语言和国家 346 9.6.3 完成程序国际化 347 9.6.4 使用MessageFormat处理包含占位符的字符串 349 9.6.5 使用类文件代替资源文件 350 9.6.6 使用NumberFormat格式化数字 350 9.6.7 使用...

    ssh(structs,spring,hibernate)框架中的上传下载

     文件数据存储在Blob类型的FILE_CONTENT表字段上,在Spring中采用OracleLobHandler来处理Lob字段(包括Clob和Blob),由于在程序中不需要引用到oracle数据驱动程序的具体类且屏蔽了不同数据库处理Lob字段方法上的...

    JAVA上百实例源码以及开源项目源代码

    Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印  util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印...

    JAVA上百实例源码以及开源项目

    Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印  util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印...

Global site tag (gtag.js) - Google Analytics