Mybatis集成MySQL使用游标查询处理大批量数据方式

 更新时间:2024年01月27日 09:50:12   作者:WannaRunning  
这篇文章主要介绍了Mybatis集成MySQL使用游标查询处理大批量数据方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

背景

基于数据的时间范围查询,给符合条件的用户推送积分即将到期的提醒。

初期用户量小使用最普通简单的分页查询扫描数据处理数据没问题。随着用户量的上升表数据已经上千万,每天扫描处理的数量也超百万,limit分页出现了慢sql,任务执行时间也达不到预期了。

上述方案出现瓶颈后考虑放弃limit方案,使用游标的方式进行全量数据的获取,这样一来SQL执行快任务执行也快。

MySQL游标查询

useCursorFetch

使用游标查询时,必须在jdbc url上设置连接属性参数useCursorFetch=true

FetchSize

在设置了useCursorFetch=true后,需要在SQL中指定fetchSize,即一次获取的数据量。

如果不设置fetchSize参数,则执行时仍然是全量返回,可能会出现OOM。

Mybatis集成Cursor查询

mapper接口方法返回值声明为Cursor类型,下面是SQL和Mapper的示例。

Cursor<Long> selectExpireCouponMember(@Param("endTime") String endTime);
 
 
<select id="selectExpireCouponMember" resultType="java.lang.Long" fetchSize="5000">
	select
		distinct member_id
	from t_dj_coupon
	where
	   end_time > end_time < #{endStartTime} and end_time < #{endTime}
</select>

下面是基于上面的SQL做大量数据查询后写入文件的代码示例。

String fileName = DateFormatUtils.format(System.currentTimeMillis(), DateUtils.PATTERN_YYYY_MM_DD) + "_status_push_member.txt";
File file = new File(fileName);
file.createNewFile();
 
fileWriter = new FileWriter(file);
bufferedWriter = new BufferedWriter(fileWriter);
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
	DjCouponMapper mapper = sqlSession.getMapper(DjCouponMapper.class);
	try (Cursor<Long> cursor = mapper.selectStartCouponMember(startDate, startDateEnd, BrandContextHolder.getBrandMdCode())) {
		Iterator<Long> iterator = cursor.iterator();
		Set<Long> couponMemberSet = new HashSet<>(pageSize.intValue());
		while (iterator.hasNext()) {
			couponMemberSet.add(iterator.next());
			writeNum++;
			if (couponMemberSet.size() >= pageSize) {
				bufferedWriter.write(couponMemberSet.toString());
				bufferedWriter.newLine();
				bufferedWriter.flush();
				writeLine++;
				couponMemberSet.clear();
			}
		
		}
		if (CollectionUtils.isNotEmpty(couponMemberSet)) {
			bufferedWriter.write(couponMemberSet.toString());
			bufferedWriter.newLine();
			bufferedWriter.flush();
			writeLine++;
		}
	}
}

Mybatis是如何实现基于Cursor查询的

com.mysql.cj.jdbc.result.ResultSetImpl实现类

ResultSetImpl 是mybatis中实现游标查询结果解析的类。

这个实现类的next方法中调用了ResultsetRows接口的next方法。

ResultsetRows接口

ResultsetRows接口有ResultsetRowsCursor,ResultsetRowsStatic,ResultsetRowsStreaming三个实现类。

本文写的游标查询的场景,使用的是ResultsetRowsCursor这个实现类。

详细看下ResultsetRowsCursor这个实现类,主要是实现了Iterator的hasNext和next方法,这也是使用Cursor获取数据需要的两个方法。

下面是hasnext方法的逻辑,根据下次要获取的游标索引和当前本地数据集计算返回是否还有后续数据可以获取。

下面是next方法的逻辑,先执行一下hasnext的逻辑判断,再取值

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 浅谈MySQL中用什么数据类型存IP地址

    浅谈MySQL中用什么数据类型存IP地址

    MySQL中用什么数据类型存IP地址?在MySQL中,当存储IPv4地址时,应该使用32位的无符号整数来存储IP地址,而不是使用字符串,本文就介绍一下这几种情况,感兴趣的可以了解一下
    2023-08-08
  • 图文详解mysql中with...as用法

    图文详解mysql中with...as用法

    这篇文章主要给大家介绍了关于mysql中with...as用法的相关资料,文中通过实例代码介绍的非常详细,对大家学习或者使用mysql具有一定的参考学习价值,需要的朋友可以参考下
    2022-01-01
  • MySQL 触发器定义与用法简单实例

    MySQL 触发器定义与用法简单实例

    这篇文章主要介绍了MySQL 触发器定义与用法,结合简单实例形式总结分析了mysql触发器的语法、原理、定义及使用方法,需要的朋友可以参考下
    2019-09-09
  • 使用YUM在Linux(CentOS 7)下安装mysql 5.7.18的教程详解

    使用YUM在Linux(CentOS 7)下安装mysql 5.7.18的教程详解

    这篇文章主要介绍了使用YUM在Linux(CentOS 7)下安装mysql 5.7.18的教程详解,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-05-05
  • MySQL如何实现事务的ACID

    MySQL如何实现事务的ACID

    这篇文章主要介绍了MySQL如何实现事务的四大特性,帮助大家更好的理解和学习MySQL数据库,感兴趣的朋友可以了解下
    2020-09-09
  • Docker启动mysql配置实现过程

    Docker启动mysql配置实现过程

    这篇文章主要介绍了Docker启动mysql配置实现过程,文中附含详细的图文示例,有需要的朋友可以借鉴参考下,希望可以有所帮助,祝大家早日升职加薪
    2021-09-09
  • 如何解决安装MySQL5.0后出现1607异常

    如何解决安装MySQL5.0后出现1607异常

    小伙们在安装mysql5.0的时候是不是遇到过1607异常问题,大家都是怎么解决的呢?下面小编跟大家分享我是如何解决安装MySQL5.0后出现1607异常的,需要的朋友可以参考下
    2015-10-10
  • 一个 20 秒 SQL 慢查询优化处理方案

    一个 20 秒 SQL 慢查询优化处理方案

    这篇文章主要分享一个 20 秒 SQL 慢查询优化的经历与处理方案,页面无法正确获取数据,经排查原来是接口调用超时,而最后发现是因为SQL查询长达到20多秒而导致了问题的发生,下面来看问题具体介绍吧
    2022-01-01
  • 服务器不支持 MySql 数据库的解决方法

    服务器不支持 MySql 数据库的解决方法

    出现问题:报错“服务器不支持 MySql 数据库”,改函数function_exists('mysql_connect')返回 false
    2013-03-03
  • Mysql服务器的启动与停止(一)

    Mysql服务器的启动与停止(一)

    Mysql服务器的启动与停止(一)...
    2006-11-11

最新评论