首页 » 网站建设 » phpmybatis流式查询技巧_查询切切数据除了分页还有mybatis效率更高的流式查询

phpmybatis流式查询技巧_查询切切数据除了分页还有mybatis效率更高的流式查询

访客 2024-11-17 0

扫一扫用手机浏览

文章目录 [+]

基本观点

流式查询指的是查询成功后不是返回一个凑集而是返回一个迭代器,运用每次从迭代器取一条查询结果。
流式查询的好处是能够降落内存利用。

如果没有流式查询,我们想要从数据库取 1000 万条记录而又没有足够的内存时,就不得不分页查询,而分页查询效率取决于表设计,如果设计的不好,就无法实行高效的分页查询。
因此流式查询是一个数据库访问框架必须具备的功能。

phpmybatis流式查询技巧_查询切切数据除了分页还有mybatis效率更高的流式查询

流式查询的过程当中,数据库连接是保持打开状态的,因此要把稳的是:实行一个流式查询后,数据库访问框架就不卖力关闭数据库连接了,须要运用在取完数据后自己关闭。

phpmybatis流式查询技巧_查询切切数据除了分页还有mybatis效率更高的流式查询
(图片来自网络侵删)
MyBatis 流式查询接口

MyBatis 供应了一个叫

org.apache.ibatis.cursor.Cursor

的接口类用于流式查询,这个接口继续了 java.io.Closeable 和 java.lang.Iterable 接口,由此可知

1、 Cursor 是可关闭的;

2、 Cursor 是可遍历的。

除此之外,Cursor 还供应了三个方法:

1、 isOpen():用于在取数据之前判断 Cursor 工具是否是打开状态。
只有当打开时 Cursor 才能取数据;

2、 isConsumed():用于判断查询结果是否全部取完。

3、 getCurrentIndex():返回已经获取了多少条数据

由于 Cursor 实现了迭代器接口,因此在实际利用当中,从 Cursor 取数据非常大略:

cursor.forEach(rowObject -> {...});但构建 Cursor 的过程不大略

我们举个实际例子。
下面是一个 Mapper 类:

@MapperpublicinterfaceFooMapper{ @Select("select from foo limit #{limit}") Cursor<Foo> scan(@Param("limit") int limit);}

方法 scan() 是一个非常大略的查询。
通过指定 Mapper 方法的返回值为 Cursor 类型,MyBatis 就知道这个查询方法一个流式查询。

然后我们再写一个 SpringMVC Controller 方法来调用 Mapper(无关的代码已经省略):

@GetMapping("foo/scan/0/{limit}")publicvoid scanFoo0(@PathVariable("limit") int limit) throwsException{ try(Cursor<Foo> cursor = fooMapper.scan(limit)) { // 1 cursor.forEach(foo -> {}); // 2 }}

上面的代码中,fooMapper 是 @Autowired 进来的。
注释 1 处调用 scan 方法,得到 Cursor 工具并担保它能末了关闭;2 处则是从 cursor 中取数据。

上面的代码看上去没什么问题,但是实行 scanFoo0() 时会报错:

java.lang.IllegalStateException: A Cursoris already closed.

这是由于我们前面说了在取数据的过程中须要保持数据库连接,而 Mapper 方法常日在实行完后连接就关闭了,因此 Cusor 也一并关闭了。

以是,办理这个问题的思路不繁芜,保持数据库连接打开即可。
我们至少有三种方案可选。

方案一:SqlSessionFactory

我们可以用 SqlSessionFactory 来手工打开数据库连接,将 Controller 方法修正如下:

@GetMapping("foo/scan/1/{limit}")publicvoid scanFoo1(@PathVariable("limit") int limit) throwsException{ try( SqlSession sqlSession = sqlSessionFactory.openSession(); // 1 Cursor<Foo> cursor = sqlSession.getMapper(FooMapper.class).scan(limit) // 2 ) { cursor.forEach(foo -> { }); }}

上面的代码中,

1 处我们开启了一个 SqlSession (实际上也代表了一个数据库连接),并担保它末了能关闭;

2 处我们利用 SqlSession 来得到 Mapper 工具。
这样才能担保得到的 Cursor 工具是打开状态的。

方案二:TransactionTemplate

在 Spring 中,我们可以用 TransactionTemplate 来实行一个数据库事务,这个过程中数据库连接同样是打开的。
代码如下:

@GetMapping("foo/scan/2/{limit}")publicvoid scanFoo2(@PathVariable("limit") int limit) throwsException{ TransactionTemplate transactionTemplate = newTransactionTemplate(transactionManager); // 1 transactionTemplate.execute(status -> { // 2 try(Cursor<Foo> cursor = fooMapper.scan(limit)) { cursor.forEach(foo -> { }); } catch(IOException e) { e.printStackTrace(); } returnnull; });}

上面的代码中,

1 处我们创建了一个 TransactionTemplate 工具(此处 transactionManager 是怎么来的不用多阐明,本文假设读者对 Spring 数据库事务的利用比较熟习了)。

2 处实行数据库事务,而数据库事务的内容则是调用 Mapper 工具的流式查询。
把稳这里的 Mapper 工具无需通过 SqlSession 创建。

方案三:@Transactional 表明

这个实质上和方案二一样,代码如下:

@GetMapping("foo/scan/3/{limit}")@Transactionalpublicvoid scanFoo3(@PathVariable("limit") int limit) throwsException{ try(Cursor<Foo> cursor = fooMapper.scan(limit)) { cursor.forEach(foo -> { }); }}

它仅仅是在原来方法上面加了个 @Transactional 表明。
这个方案看上去最简洁,但请把稳 Spring 框架当中表明利用的坑:只在外部调用时生效。
在当前类中调用这个方法,依旧会报错。

以上是三种实现 MyBatis 流式查询的方法。

标签:

相关文章

php为无色透明技巧_水货钻石其实也还行

从各种钻石中,可以看到大大小小的“包裹体” 图片来源:参考文献包裹体的种类多样。比钻石形成更早的包裹体,叫“原生包裹体”;与钻石同...

网站建设 2024-12-19 阅读0 评论0

phpstudy发送gbk技巧_php的文件上传

这里首先声明一下这一章的内容比较多,比较难,你要抱着和自己去世磕的态度。细微之处不放过,多敲多练是王道。 学习就像爬山,得一步一步...

网站建设 2024-12-19 阅读0 评论0