流式查询 指的是查询成功后不是返回一个集合而是返回一个迭代器,应用可以通过迭代器每次取一条查询结果。流式查询的好处是能够降低内存使用。
例如我们想要从数据库取 1000 万条记录而又没有足够的内存时,就不得不分页查询。而分页查询就需要我们按照顺序查询并设置一个参数来记录当前进度并在下次查询时将进度作为参数传入(比如按id升序查询,记录每次查询结果的最大id, 下次查询将这个最大id传入只查询大于这个id的),否则就会出现深度分页的情况。而查询效率取决于表设计,如果设计的不好,那么每次查询都会是一次单独的低效查询。
而流式查询不需要自己记录进度(数据库来记录),且即使表设计的较差或在sql比较复杂,也仅仅只需要一次低效查询。
流式查询的过程当中,要保证数据库连接是保持打开状态的,否则就会流关闭。
MyBaits通过游标Cursor实现了流式查询。 MyBaits Plus基于Mybais, 自然也是支持的。
不需要其他配置, 像平常我们写查询一样在Mapper定义查询,并将返回结果设为Cursor即可实现一个流式查询。
sql也正常按照时间查询条件写,不需要加limit之类的参数。
Cursor<MyDbTableDo> queryByCursor()
上面提过,使用流式查询需要保证数据库连接是保持打开状态。而正常情况下我们使用mybaits执行一次查询,连接都会被关闭或在重置。因此我们需要一些方法来保持连接。
事务执行完毕之前连接会一直保持因此,我们可以来使用事务来保持连接。
@Transactional
public void transactionalAnno() throws Exception {
try (Cursor<MyDbTableDo> cursor = myDbTableMapper.queryByCursor()) {
cursor.forEach(item -> { });
}
}
这是最简单的方法,但是需要注意的是,由于cursor在遍历结束的方法末尾后会主动关闭连接。因此:
public void transactionTemplate() throws Exception {
TransactionTemplate transactionTemplate =
new TransactionTemplate(transactionManager);
transactionTemplate.execute(status -> {
try (Cursor<MyDbTableDo> cursor = myDbTableMapper.queryByCursor()) {
cursor.forEach(item -> { });
} catch (IOException e) {
e.printStackTrace();
}
return null;
});
}
在 Spring 中,用 TransactionTemplate 来执行一个数据库事务,这个过程中数据库连接同样是打开的
SqlSessionFactory 来手工打开数据库连接,SqlSessionFactory直接注入即可,MyBatis维护了这个Bean.
public void sqlSessionFactory() throws Exception {
try (
SqlSession sqlSession = sqlSessionFactory.openSession();
Cursor<MyDbTableDo> cursor = myDbTableMapper.queryByCursor();
) {
cursor.forEach(item -> { });
}
}
开启一个 SqlSession (实际上也代表了一个数据库连接),并保证它最后能关闭;然后使用 SqlSession 来获得 Mapper 对象。这样才能保证得到的 Cursor 对象是打开状态的。
Cursor继承了迭代器,可以通过Cursor获取他的Iterator, 或者直接使用for循环来获取数据。
需要注意的是,Cursor在查询一瞬间数据就固化了,如果你先查询,再更新,再遍历,即使在同一个事务里面,获得的结果也是未更新的数据。
cursor在遍历结束后会主动关闭连接。如果未遍历结束中途退出,可以调用cursor的close方法关闭连接。推荐finaly内总是调用close或者try(resoure)来保证连接总是被正常关闭。
参考资料:
你还在用分页?试试 MyBatis 流式查询,真心强大!
PS:
【JAVA核心知识】系列导航 [持续更新中…]
关联导航:MySQL架构基础
关联导航:MySQL数据类型选择与设计
关联导航:创建高性能的索引
关联导航:查询性能优化
关联导航:EXPLAIN的使用
关联导航:深度了解MySql的InnoDB引擎
欢迎关注…