IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> No statements may be issued when any streaming result sets are open and in use on a given connection -> 正文阅读

[大数据]No statements may be issued when any streaming result sets are open and in use on a given connection

引言

本文整理了 MySQL 流式查询一些原理和用法, 包括 MySQL 官方文档对于 ResultSet 流式查询的说明以及很多网友关于 MySQL 流失查询踩坑的说明. 最后给出了解决流式查询的 connection 在未查询完结果集的数据之前又被其他地方使用导致报错的解决方法, 希望能对读者有所帮助.

原文地址: No statements may be issued when any streaming result sets are open and in use on a given connection

欢迎访问我的博客: http://blog.duhbb.com/

报错日志

org.springframework.dao.DataAccessResourceFailureException: PreparedStatementCallback; SQL []; Could not create connection to database server. Attempted reconnect 3 times. Giving up.; nested exception is java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
	at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:81)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
	at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1443)
	at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633)
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:669)
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:700)
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:712)
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:763)
	at org.springframework.jdbc.core.JdbcTemplate.queryForList(JdbcTemplate.java:829)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)
	at org.springframework.jdbc.core.JdbcTemplate$RowCallbackHandlerResultSetExtractor.extractData(JdbcTemplate.java:1607)
	at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:679)
	at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:669)
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:694)
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:73)
	at com.mysql.cj.jdbc.ConnectionImpl.connectWithRetries(ConnectionImpl.java:903)
	at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:828)
	at com.mysql.cj.jdbc.ConnectionImpl.handleReconnect(ConnectionImpl.java:2694)
	at com.mysql.cj.NativeSession.invokeReconnectListeners(NativeSession.java:1215)
	at com.mysql.cj.NativeSession.execSQL(NativeSession.java:1067)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:930)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1003)
	at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
	at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
	at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:678)
	at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)
	... 69 common frames omitted
Caused by: java.sql.SQLException: Streaming result set com.mysql.cj.protocol.a.result.ResultsetRowsStreaming@5869a708 is still active. No statements may be issued when any streaming result sets are open and in use on a given connection. Ensure that you have called .close() on any active streaming result sets before attempting more queries.
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
	at com.mysql.cj.jdbc.ConnectionImpl.pingInternal(ConnectionImpl.java:1524)
	at com.mysql.cj.jdbc.ConnectionImpl.connectWithRetries(ConnectionImpl.java:848)
	... 79 common frames omitted

MySQL 结果集官方解释

原文地址: 6.4 JDBC API Implementation Notes

结果集

默认情况下, ResultSet 被完全检索并存储在内存中. 在大多数情况下, 这是最有效的操作方式, 并且由于 MySQL 网络协议的设计, 更容易实现. 如果您正在使用具有大量行或大值的 ResultSet, 并且无法在 JVM 中为所需的内存分配堆空间, 您可以告诉驱动程序一次将结果流回一行.

Statement 要启用此功能, 请按以下方式创建实例:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);

给结果集设置 forward-only, read-only 以及将 fetch size 设置为 Integer.MIN_VALUE, 即表明让 MySQL 以流式传输结果集中的数据. 在此之后, 将逐行检索使用该语句创建的任何结果集.

这种方法有一些注意事项. 您必须先读取结果集中的所有行 (或将其关闭), 然后才能对连接发出任何其他查询, 否则将引发异常.

这些语句持有的锁最早可以被释放 (无论它们是 MyISAM 表级锁还是其他存储引擎中的行级锁, 例如 InnoDB) 是在语句完成时.

如果语句在事务范围内, 则在事务完成时释放锁 (这意味着语句需要先完成). 与大多数其他数据库一样, 在读取语句上所有待处理的结果或关闭语句的活动结果集之前, 语句是不完整的.

因此, 如果使用流式结果, 如果您想保持对生成结果集的语句所引用的表的并发访问, 请尽快处理它们.

另一种选择是每次使用基于游标的流来检索一组行. 这可以通过将连接属性 useCursorFetch 设置为 true, 然后调用 setFetchSize(int) 来设置每次要获取的行数:

conn = DriverManager.getConnection("jdbc:mysql://localhost/?useCursorFetch=true", "user", "s3cr3t");
stmt = conn.createStatement();
stmt.setFetchSize(100);
rs = stmt.executeQuery("SELECT * FROM your_table_here");

原因分析

来自网友的分析

以下错误消息 “流式传输结果集 com.mysql.jdbc.RowDataDynamic@XXXXXX 仍然处于活动状态. 当任何流式传输结果集打开并在给定连接上使用时, 不会发出任何语句. 确保您已调用 .close() 在尝试更多查询之前在任何活动的流式传输结果集上” 来自 MySQL.

原因在于 MySQL 的流模式, Streaming 模式是从 MySQL 获取数据的最快方式.

但是, 流模式有一个限制: 当结果集在 MySQL 连接上以流模式打开时, 您不能使用同一数据库连接来运行其他查询. 这正是上面的错误消息所告诉的. 该问题的解决方案是将 MySQL 连接设置更改为使用 CursorFetch 模式而不是 Streaming 模式.

CursorFetch 是 MySQL 中第二快的读取方法. 不同之处在于, 在 Streaming 模式下, 服务器尝试立即开始将数据发送给消费者, 在 CursorFetch 上, 它首先填充缓冲区, 然后从缓冲区提供数据. 在非常大的数据集上, 在 MySQL 开始以 CursorFetch 模式为您获取数据之前会有一些初始延迟, 但对于任何实际目的而言, 差异通常可以忽略不计.

以上来自: Error-message-Streaming-result-set-com-mysql-jdbc-RowDataDynamic

流式查询与 fetchsize

既然 fetchsize 这么好用, 那 MySQL 直接设一个值, 不就也可以用到缓冲区, 不必每次都将全量结果集装入内存. 但是, 非常遗憾, MySQL 的 JDBC 驱动本质上并不支持设置 fetchsize, 不管设置多大的 fetchsize, JDBC 驱动依然会将 select 的全部结果都读取到客户端后再处理, 这样的话当 select 返回的结果集非常大时将会撑爆 Client 端的内存.

但也不是完全没办法, PreparedStatement/StatementsetFetchSize 方法设置为 Integer.MIN_VALUE 或者使用方法 Statement.enableStreamingResults(), 也可以实现流式查询, 在执行 ResultSet.next() 方法时, 会通过数据库连接一条一条的返回, 这样也不会大量占用客户端的内存.

MySQL 流式查询的坑

其实 MySQL 本身并没有 FetchSize 方法, 它是通过使用 CS 阻塞方式的网络流控制实现服务端不会一下发送大量数据到客户端撑爆客户端内存, 这种实现方式比起商业数据库 Oracle 使用客户端, 服务器端缓冲块暂存查询结果数据来说, 简直是弱爆了! 这样带来的问题: 如果使用了流式查询, 一个 MySQL 数据库连接同一时间只能为一个 ResultSet 对象服务, 并且如果该 ResultSet 对象没有关闭, 势必会影响其他查询对数据库连接的使用! 此为大坑, 难怪 sharding-sphere 费劲心思要提供两种数据库连接模式, 如果应用对数据库连接的消耗要求严苛, 那么流式查询就不再适合.

以上来自: 深入了解 MySQL 的流式查询机制

解决方案

用了 jdbcTemplate 进行流式查询, 然后在流式查询的 callback 中又调用 jdbcTemplate 查询其他相关数据. 生产环境出现了这个问题, 但是本地没有复现.

解决方法: 直接用原始的 jdbc connection 查询, 避免 connection 进行流式查询的时候又被别的地方使用了.

原文地址: No statements may be issued when any streaming result sets are open and in use on a given connection

欢迎访问我的博客: http://blog.duhbb.com/

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 10:53:18  更:2022-07-03 10:55:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 2:54:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码