Mybatis游标查询大量数据方式
程序员文章站
2022-06-09 21:04:38
目录mybatis游标查询大量数据mapper层service层资源释放mybatis游标使用总结什么是游标mybatis游标查询大量数据对大量数据进行处理时,为防止内存泄漏情况发生,所以采用myba...
mybatis游标查询大量数据
对大量数据进行处理时,为防止内存泄漏情况发生,所以采用mybatis plus游标方式进行数据查询处理,当查询百万级的数据的时候,使用游标可以节省内存的消耗,不需要一次性取出所有数据,可以进行逐条处理或逐条取出部分批量处理
mapper层
- 使用cursor类型进行数据接收
- @options,fetchsize设置为integer最小值
- @select,写查询sql
@options(resultsettype = resultsettype.forward_only, fetchsize = integer.min_value) @select("select domain from illegal_domain where icpstatus != #{icpstatus}") cursor<illegaldomain> getdayjobdomain(@param("icpstatus") integer icpstatus);
service层
cursor<illegaldomain> domainlist = illegaldomainmapper.getdayjobdomain(1);
数据处理
foreach方式
domainlist.foreach(illegaldomain -> { //处理逻辑,根据业务需求自行完成 future<icpstatusvo> future = checkicpthreadpool.submit(new icpcheckthread(illegaldomain.getdomain(), configmap)); results.add(future); });
迭代器
iterator<illegaldomain> iter = domainlist.iterator(); while (iter.hasnext()) { <!--// fetch next 10 employees--> <!--for(int i = 0; i<10 && iter.hasnext(); i++) {--> <!-- smallchunk.add(iter.next());--> <!--}--> //处理逻辑,根据业务需求自行完成 future<icpstatusvo> future = checkicpthreadpool.submit(new icpcheckthread(illegaldomain.getdomain(), configmap)); results.add(future); }
资源释放
使用完毕后,在finally块释放资源,否则游标不关闭也可能会导致内存溢出问题
try{ //your code } catch (exception e) { log.error(e); } finally { if(null != domainlist){ try { domainlist.close(); } catch (ioexception e) { e.printstacktrace(); } } }
mybatis游标使用总结
当查询百万级的数据的时候,查询出所有数据并放入内存中时会发生oom(outofmemoryexception),使用游标可以节省内存的消耗,不需要一次性取出所有数据,可以进行逐条处理或逐条取出部分批量处理,在此场景下就可以使用游标的概念来解决这个问题。
什么是游标
游标(cursor)是处理数据的一种方法,为了查看或者处理结果集中的数据,游标提供了在结果集中一次一行或者多行前进或向后浏览数据的能力。
demo:
// 第一种 @options(resultsettype = resultsettype.forward_only) @select("select * from department where status = 0") list<departmententity> querydepartmentall(); // 第二种 在mybatis-3.4.0版本中,不支持@select注解,在3.4.1版本中已经修复: @options(resultsettype = resultsettype.forward_only) @select("select * from department where status = 0") cursor<employee> cursorquerydepartmentall();
@service public class departmentserviceimpl implements departmentservice { private static final logger log = loggerfactory.getlogger(departmentserviceimpl.class); @autowired private departmentdao departmentdao; @autowired private sqlsessiontemplate sqlsessiontemplate; public list<departmentdto> getdepartmentlist(departmentsearchparam param) { cursor<object> cursor = null; sqlsession sqlsession = null; try { sqlsession = sqlsessiontemplate.getsqlsessionfactory().opensession(); cursor = sqlsession.selectcursor(departmentdao.class.getname() + ".querydepartmentall"); cursor.foreach(e -> { // 处理逻辑 }); // 也可以使用迭代器:iterator<object> iterator = cursor.iterator(); } catch (exception e) { e.printstacktrace(); } finally { if (null != cursor) { try { cursor.close(); } catch (exception e) { log.error(e.getmessage(), e); } } if (null != sqlsession) { try { sqlsession.close(); } catch (exception e) { log.error(e.getmessage(), e); } } } } }
-
resultset.type_forword_only
结果集的游标只能向下滚动。 -
resultset.type_scroll_insensitive
结果集的游标可以上下移动,当数据库变化时,当前结果集不变。 -
resultset.type_scroll_sensitive
返回可滚动的结果集,当数据库变化时,当前结果集同步改变。
注意:游标是可以前后移动的。如果resultsettype = type_scroll_insensitive ,就是设置游标就可以前后移动。
mybatis为了保证可以前后移动,mybatis会把之前查询的数据一直保存在内存中。
所以并不能根本解决oom,所以我们这里需要设置为@options(resultsettype = resultsettype.forward_only)(其实默认就是resultsettype.forward_only)
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
上一篇: 使用Docker部署war包项目的实现
推荐阅读
-
mybatis查询语句的背后之封装数据
-
MyBatis之自查询使用递归实现 N级联动效果(两种实现方式)
-
详解SQL Server数据库链接查询的方式
-
mybatis批量insert数据动态表明(mysql批量insert正确方式)
-
mybatis批量insert数据动态表明(mysql批量insert正确方式)
-
MyBatis之自查询使用递归实现 N级联动效果(两种实现方式)
-
MyBatis从入门到精通(三):MyBatis XML方式的基本用法之多表查询
-
基于mybatis batch实现批量提交大量数据
-
关于MyBatis 查询数据时属性中多对一的问题(多条数据对应一条数据)
-
PHP查询MySQL大量数据的时候内存占用分析