MyBatis数千万的数据查询解决方案避免了OOM
流查询意味着在成功查询之后,应用程序每次都从迭代器中获取一个查询结果,而不是返回一个集合,而是一个迭代器。流查询的优点是它可以减少内存使用量。
如果没有流查询,则当我们想从数据库中获取1000万条记录并且没有足够的内存时,我们必须进行页面查询,而页面查询的效率取决于表的设计。如果设计不好,将无法执行有效的分页查询。
因此,流查询是数据库访问框架的必要功能。在流查询的过程中,数据库连接保持打开状态,因此应注意,在执行流查询后,数据库访问框架不负责关闭数据库连接,应用程序需要在获取数据后将其关闭。
。 MyBatis流查询界面MyBatis提供了一个名为org.apache.ibatis.cursor.Cursor的接口类,用于流查询。
此接口继承java.io.Closeable和java.lang.Iterable接口。从中我们可以看到:游标可以关闭;游标是可遍历的。
此外,Cursor还提供了三种方法:isOpen():用于在获取数据之前确定Cursor对象是否处于打开状态。游标只能在打开时才能获取数据。
isConsumed():用于判断查询结果是否全部被获取。 getCurrentIndex():返回已获取多少数据。
因为Cursor实现了迭代器接口,所以在实际使用中从Cursor中获取数据非常简单:cursor.forEach(rowObject& nbsp;-& nbsp; {...});但是构建游标的过程并不简单。让我们举一个实际的例子。
这是一个Mapper类:@Mapper公共接口FooMapper {@Select(“ select& nbsp; *& nbsp; foo& nbsp; limit& nbsp;#{limit}”)Cursorscan(@Param( “ limit()” int limit);}方法scan()是一个非常简单的查询。通过将Mapper方法的返回值指定为Cursor类型,MyBatis知道此查询方法是流查询。
然后,我们编写另一个SpringMVC Controller方法来调用Mapper(不相关的代码已被省略):@GetMapping(“ foo / scan / 0 / {limit}”)public void scanFoo0(@PathVariable(“ limit”)int limit)抛出异常{}); //& nbsp; 2}}在上面的代码中,fooMapper由@Autowired传入。注意1调用scan方法获取Cursor对象并确保最终可以将其关闭;注意2是从游标中获取数据。
上面的代码似乎没问题,但是在执行scanFoo0()时将报告错误:java.lang.IllegalStateException:Cursor& is& nbsp;已经关闭。这是因为我们前面说过,在获取数据的过程中需要保留它。
数据库连接,Mapper方法通常在执行后关闭连接,因此Cusor也被关闭。因此,解决此问题的想法并不复杂,只需保持数据库连接打开即可。
我们至少有三个选择。解决方案1:SqlSessionFactory我们可以使用SqlSessionFactory手动打开数据库连接,如下修改Controller方法:@GetMapping(“ foo / scan / 1 / {limit}”)public void scanFoo1(@PathVariable(“ limit”); )int limit)引发异常{try(& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp; SqlSession& nbsp; sqlSession& nbsp; = & nbsp; sqlSessionFactory.openSession(); //  1游标  =& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp; & nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp; sqlSession.getMapper(FooMapper.class).scan(limit)& nbsp;& ;  //& nbsp; 2& nbsp;& nbsp;& nbsp;){& nbsp;& nbsp;& nbsp;& nbsp;& nbsp ;& nbsp;& nbsp; cursor.forEach(foo& nbsp;-& nbsp; {& nbsp;});& nbsp;& nbsp;& nbsp; & nbsp;}}上面的代码首先,我们打开了一个SqlSess离子(实际上代表数据库连接),并确保可以在最后关闭它;其次,我们使用SqlSession来获取Mapper对象。
这样,可以确保获得的光标对象是打开的。解决方案2:TransactionTemplate在Spring中,我们可以使用TransactionTemplate执行数据库事务,在此期间还将打开数据库连接。
代码如下:@GetMapping(“ foo / scan / 2 / {limit}”)public void scanFoo2(@PathVariable(“ limit”)int limit)引发异常{& nbsp;& nbsp;& amp; ; nbsp;& nbsp; TransactionTemplate& nbsp; transactionTemplate  =新的TransactionTemplate(transactionManager); //  1 transactionTemplate.execute(status& n。
如果没有流查询,则当我们想从数据库中获取1000万条记录并且没有足够的内存时,我们必须进行页面查询,而页面查询的效率取决于表的设计。如果设计不好,将无法执行有效的分页查询。
因此,流查询是数据库访问框架的必要功能。在流查询的过程中,数据库连接保持打开状态,因此应注意,在执行流查询后,数据库访问框架不负责关闭数据库连接,应用程序需要在获取数据后将其关闭。
。 MyBatis流查询界面MyBatis提供了一个名为org.apache.ibatis.cursor.Cursor的接口类,用于流查询。
此接口继承java.io.Closeable和java.lang.Iterable接口。从中我们可以看到:游标可以关闭;游标是可遍历的。
此外,Cursor还提供了三种方法:isOpen():用于在获取数据之前确定Cursor对象是否处于打开状态。游标只能在打开时才能获取数据。
isConsumed():用于判断查询结果是否全部被获取。 getCurrentIndex():返回已获取多少数据。
因为Cursor实现了迭代器接口,所以在实际使用中从Cursor中获取数据非常简单:cursor.forEach(rowObject& nbsp;-& nbsp; {...});但是构建游标的过程并不简单。让我们举一个实际的例子。
这是一个Mapper类:@Mapper公共接口FooMapper {@Select(“ select& nbsp; *& nbsp; foo& nbsp; limit& nbsp;#{limit}”)Cursorscan(@Param( “ limit()” int limit);}方法scan()是一个非常简单的查询。通过将Mapper方法的返回值指定为Cursor类型,MyBatis知道此查询方法是流查询。
然后,我们编写另一个SpringMVC Controller方法来调用Mapper(不相关的代码已被省略):@GetMapping(“ foo / scan / 0 / {limit}”)public void scanFoo0(@PathVariable(“ limit”)int limit)抛出异常{}); //& nbsp; 2}}在上面的代码中,fooMapper由@Autowired传入。注意1调用scan方法获取Cursor对象并确保最终可以将其关闭;注意2是从游标中获取数据。
上面的代码似乎没问题,但是在执行scanFoo0()时将报告错误:java.lang.IllegalStateException:Cursor& is& nbsp;已经关闭。这是因为我们前面说过,在获取数据的过程中需要保留它。
数据库连接,Mapper方法通常在执行后关闭连接,因此Cusor也被关闭。因此,解决此问题的想法并不复杂,只需保持数据库连接打开即可。
我们至少有三个选择。解决方案1:SqlSessionFactory我们可以使用SqlSessionFactory手动打开数据库连接,如下修改Controller方法:@GetMapping(“ foo / scan / 1 / {limit}”)public void scanFoo1(@PathVariable(“ limit”); )int limit)引发异常{try(& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp; SqlSession& nbsp; sqlSession& nbsp; = & nbsp; sqlSessionFactory.openSession(); //  1游标  =& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp; & nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp;& nbsp; sqlSession.getMapper(FooMapper.class).scan(limit)& nbsp;& ;  //& nbsp; 2& nbsp;& nbsp;& nbsp;){& nbsp;& nbsp;& nbsp;& nbsp;& nbsp ;& nbsp;& nbsp; cursor.forEach(foo& nbsp;-& nbsp; {& nbsp;});& nbsp;& nbsp;& nbsp; & nbsp;}}上面的代码首先,我们打开了一个SqlSess离子(实际上代表数据库连接),并确保可以在最后关闭它;其次,我们使用SqlSession来获取Mapper对象。
这样,可以确保获得的光标对象是打开的。解决方案2:TransactionTemplate在Spring中,我们可以使用TransactionTemplate执行数据库事务,在此期间还将打开数据库连接。
代码如下:@GetMapping(“ foo / scan / 2 / {limit}”)public void scanFoo2(@PathVariable(“ limit”)int limit)引发异常{& nbsp;& nbsp;& amp; ; nbsp;& nbsp; TransactionTemplate& nbsp; transactionTemplate  =新的TransactionTemplate(transactionManager); //  1 transactionTemplate.execute(status& n。
- 电话:0797-4282799
- 邮箱:sales@tonevee.com
- 联系人:李先生 13510435585
- QQ:
- 地址:江西省赣州市定南县良富工业区电子产业区5栋

