Mysql中使用流式查询避免数据量过大导致OOM-后续

一、前言

之前http://www.jianshu.com/p/0339c6fe8b61 介绍了MySQL中三种使用流式方法,看起来很优雅,实则优雅的同时还是有一些注意事项的,下面就针对流式查询时候的注意事项进行介绍。

二、 同一个连接在游标迭代数据过程中不能被复用

2.1 简单介绍

先贴下MySQL Connector/J 5.1 Developer Guide中原文:

There are some caveats with this approach. You must read all of the rows in the result set (or close it) before you can issue any other queries on the connection, or an exception will be thrown.

Therefore, if using streaming results, process them as quickly as possible if you want to maintain concurrent access to the tables referenced by the statement producing the result set.

之所以有这个限制是因为非游标情况下我们在得到resultset后,mysqlclient已经把数据全部放到了resultset,所以这时候该数据库连接就空闲了,所以可以去执行其他查询,而流式查询时候返回给我们Resultset后,所有数据并不都在Resultset,当我们调用next时候需要使用数据库连接从Server获取数据,所以在整个数据访问完毕之前这个连接一直被占用,所以才有了同一个连接在游标迭代数据过程中不能被复用的注意事项。

2.2 一个例子

0?wx_fmt=png

0?wx_fmt=png

执行上面代码:

而第一次查询不收影响继续自己的迭代数据。

那么就来看下在第二次查询前调用close方法会有啥效果。

0?wx_fmt=png

可知在调用close时候,里面还是循环调用next尝试把剩余记录迭代出来丢弃掉。我们调用close之所以没返回,时间上是因为内部在丢弃数据中,其实文档里面说迭代数据完毕或者调用close后才能调用新的查询,其实调用close作用还是要把Resultset里面的数据迭代出来完。

那么还有一个问题,上面说同时子线程也不输出结果了,为啥那?那么我们在回顾下next方法:

0?wx_fmt=png

soga,原来调用next方面里面也是先获取链接的锁,但是这个锁现在被close方法锁持有,你可能说synchronized是可重入锁哇,为啥调用next进入不了那? 不错synchronized是可重入锁,但是调用close和调用next是不同线程哦。

三、MyBatisCursorItemReader是线程不安全的

之前文章介绍了使用MyBatisCursorItemReader可以由我们自己操作游标,使用时候在xml注入即可:

0?wx_fmt=png

当我们只有一个线程调用myMyBatisCursorItemReader进行查询操作时候,很优雅,没有问题,但是当多个线程都调用myMyBatisCursorItemReader进行open,read操作就有问题了,因为这货是线程不安全的。下面看下myMyBatisCursorItemReader代码:

0?wx_fmt=png

哦,原来下面这些变量都不是线程安全的 parameterValues;
private Cursor cursor;
private Iterator cursorIterator;

那么我们把他改造为ThreadLocal如何, 其实还是有问题,为啥那,看父类:

0?wx_fmt=png

0?wx_fmt=png

0?wx_fmt=png

因为里面还有个currentItemCount是线程不安全的,回头看,会发现这个父类对我们没有用,他的作用是限制迭代出来的记录数据,如果不需要这个限制可以不用,所以可以改造为线程安全的:

0?wx_fmt=png

0?wx_fmt=png

当然还有更简单的办法,那就是使用原型模式,每次getBean时候会重新创建一个对象。

三 、参考

  • https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-implementation-notes.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值