你的executeBatch()是批量方式执行的?确定没眼花吗?

农行数风云团队 2022-04-12 10:31:00
作者介绍

农行研发中心“数风云”团队,一支朝气蓬勃、快速成长的技术团队,始终致力于农行大数据、数据库和云计算等领域的应用实践与技术创新,探索数据赋能,勇攀数据云巅,为企业数字化转型和金融科技发展不断贡献力量。

 

日常开发中,当遇到数据的批量插入和更新等问题时经常会使用到JDBC的executeBatch()方法,来实现批量执行语句的功能。近期项目组在开发过程中,遇到了一个奇怪的现象,使用了executeBatch()方法进行批量数据处理,在测试过程中发现数据库(MySQL8.0.18)端日志收到的请求SQL仍是逐条收到的,并不是预期的批量收到请求批量执行。

 

为验证此问题,进行如下测试。通过循环的方式分别批量执行3条update语句,调试方式查看执行情况。发现数据库端日志,三条update是分别收到的,如图1所示,数据库端收到的SQL均有时间间隔。在详细调试应用端请求,发现通过executeBatch()方法实际与数据库进行了3次交互,每次仅发送了一条SQL请求(如图2 所示)。

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
String sql = "update test set name='test' where id = ?";PreparedStatement ps = conn.prepareStatement(sql); for (int i = 1; i < n ;i++) {  ps.setInt(1, i);  ps.addBatch();}ps.executeBatch();

 

图片

图1 批量执行3条SQL数据库端日志

 

图片
图2 批量执行3条SQL的详细报文中交互情况

 

这是什么原因?executeBatch()没生效?批量方法使用有问题?带着这些问题查阅MySQL驱动源码(版本8.0.18)一探究竟。分别查阅Statement和PrepareStatement的executeBatch()实现方式,发现要达到批量方式执行效果,二者均对关键属性rewriteBatchedStatements进行了判断。还可以发现当PrepareStatement中含有空语句,或实际批量执行的SQL数量未大于3条(使用Statement时未大于4条),MySQL驱动仍将继续按照单条SQL的方式进行执行,而非批量执行。因此,在JDBC连接串中增加该参数配置,如:

 

jdbc:mysql://ip:端口/mytest?rewriteBatchedStatements=true

 

设置后增多批量SQL执行数量时(如循环添加4条SQL),数据库端收到的SQL请求变为批量收到。详细调试应用端请求时,发现应用端实际与数据库交互变为1次(如图5所示),发送的报文请求是整体待执行的SQL(如图6所示)。SQL请求终于成功实现批量执行。

 

图片

图3  Statement实现的SQL批量执行逻辑

 

图片

图4  PrepareStatement现的SQL批量执行逻辑

 

图片

图5 批量执行4条SQL数据库端日志

 

图片

图6 批量执行4条SQL的详细报文中交互情况

 

除rewriteBatchedStatements参数外,驱动源码中对allowMultiQueries也进行了判断。该参数是否影响批量处理和执行呢?经查阅官网allowMultiQueries不影响addBatch()和executeBatch()的执行,该配置控允许使用“;”在一条语句中分隔多个查询

 

图片

图7 allowMultiQueries参数

 

若未设置该参数,MySQL驱动层将尝试向数据库发送开启多语句支持的请求,并在最终执行完成后,再次向数据库发送关闭多语句支持的请求。额外的开启和关闭多语句支持的请求动作,可能对一些进行了分布式事务进行多语句提交优化的分布式数据库造成影响。

 

因此,作为最佳实践,建议在jdbc参数中rewriteBatchedStatements和allowMultiQueries=true同时设置。

 

图片

图8 开启MultiQueries

 

图片

图9 发送开启MultiQueries请求

 

图片

图10 关闭MultiQueries

 

图片

图11 发送关闭MultiQueries请求

 

结论:使用JDBC的executeBatch()批量执行方法,需要JDBC参数需设置rewriteBatchedStatements=true,并且批量执行的数据大于3条,并不包含空语句时。驱动将以批量的形式进行交互。并且建议设置allowMultiQueries=true参数,可减少对数据库的额为请求。

 

dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn

最新评论
访客 2022年05月03日

写的很好呀!

访客 2022年04月07日

你好,看完文章,有点地方不太明白,想请教下两个问题…

访客 2022年03月30日

想问一下,如何才能发现数据冲突呢

访客 2022年03月30日

d

访客 2022年03月28日

梁老师,您好,看了您写的exadata image升级方案,请…

活动预告