ActiveMQ:No operations allowed after statement closed问题及解决办法

 
ActiveMQ版本:5.5.1

现象:

系统现象:部分消息发送失败,失败频率不正常。
日志信息:activemq.log 中一直有这样的错误日志:

JDBC Failure: No operations allowed after statement closed.

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after statement closed.

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)

…………

at org.apache.activemq.transport.InactivityMonitor.onCommand(InactivityMonitor.java:227)

at org.apache.activemq.transport.TransportSupport.doConsume(TransportSupport.java:83)

at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:220)

at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:202)

at java.lang.Thread.run(Thread.java:662)

Close failed: Already closed.

看上去又是 mq broker 失去了数据库连接,但代码仍尝试在此连接上执行操作,所以 jdbc 直接抛异常。

原因:

ActiveMQ 持久化方案我们选的是 MySQL 。
如果 mq 与 db 之间的数据库连接,因为数小时的不活动(inactivity),那么 MySQL 就会根据自身的 wait_timeout 参数设置主动断开连接。这一点在之前的“ActiveMQ:Communications link failure问题以及解决办法”文章中讲过。
只不过,遇到此问题时,
mq client 端报告“com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure”错误,
而 mq server 端则报告“ com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after statement closed. ”错误。
即原因是,mq broker service 试图在已关闭的数据库连接上继续执行操作
缺陷单 AMQ-2534 甚至报告“

Broker gets stuck with an error about using a closed JDBC statement

”,我们很难说此时 mq broker service 会不会真的“卡住”。
 
解决办法:

跟“ActiveMQ:Communications link failure问题以及解决办法”文章讲的一样,
最简单办法,还是根据业务特点,调整 ActiveMQ 所使用的 MySQL 的全局变量 wait_timeout 值,
尽量减少数据库连接因为 inactivity 而被关闭的几率 。
 
或者在 mq client 里主动捕获 com.mysql.jdbc.exceptions.jdbc4.CommunicationsException 异常,手动重新连接即可:
  1. } catch (SQLException sqlEx) {
  2. String sqlState = sqlEx.getSQLState();
  3. // 08S01就是这个异常的sql状态。单独处理手动重新连接即可。
  4. if ("08S01".equals(sqlState) || "40001".equals(sqlState))
 

为什么 Connector/J 不自动重连而非要抛出异常:

下面的文字翻译自 MySQL 5.5 Connect/J 疑难问题文档
23.3.15.13: 为什么遇到 communication failure 之后, Connector/J 不能自己重新连上数据库,然后重新提交事务呢,而是非要抛出一个异常,即使我用了 autoReconnect 连接字符串属性?
答:有几个原因。
第一个,保证事务完整性。MySQL 的帮助文档上曾说过:“there is no safe method of reconnecting to the MySQL server without risking some corruption of the connection state or database state information”。
可以看一下这个案例:
01.conn.createStatement().execute(
"UPDATE checking_account SET balance = balance - 1000.00 WHERE customer='Smith'");
02.conn.createStatement().execute(
"UPDATE savings_account SET balance = balance + 1000.00 WHERE customer='Smith'");
03.conn.commit();
考虑一下这个场景:执行完01后,数据库连接断了。
如果没有异常抛出的话,应用程序永远不知道这个问题,仍继续执行。
但是第一个事务并没有提交,所以它回滚了。
如果没抛异常,数据库连接自动重连,于是第二个事务被提交了。
从而破坏了事务完整性(transactional integrity)。
 
记住,此时 auto-commit 于事无补。当 Connector/J 遇到 communication problem ,你不知道服务器端是否处理了这个事务,有几种可能:
  • 服务器端没有接到这个事务,因此什么也没发生;
  • 服务器端接到了且执行了,但客户端没有收到 Response 。
 
第二个原因是,事务里上下文相关数据有可能非常脆弱,如:
  • 临时表;
  • 用户自定义变量;
  • 服务器端预处理语句(Server-side prepared statements);
如果数据库连接断开了,很可能这些数据也消失了;如果此时不抛出异常而是自动重连,你的应用程序很可能跑飞了。
 
总结:
1)silently reconnecting”可能非常不安全,将衍生出很多不可控问题。所以最佳策略是,通知应用程序到底发生了什么,然后由应用开发者决定如何处理
2)mq的生产者频繁报“com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure”和mq server自己频繁报“com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after statement closed. ”,都是因为 mysql 的 wait_timeout 导致数据库连接因为不活动而被主动关闭。
 
本文引自:http://www.cnblogs.com/zhengyun_ustc/archive/2012/11/10/activemq_inactivity.html

最新文章

  1. java面向对象_构造器
  2. MVC Html.ValidationSummary()样式优化
  3. ps 使用说明
  4. mariadb主从复制架构学习笔记
  5. WPS Office手机版调用接口代码指导帖之一(Android)
  6. 以&运行在后台的程序,关闭terminal后,相应进进程自动关闭
  7. 谈论高并发(二十二)解决java.util.concurrent各种组件(四) 深入了解AQS(二)
  8. 关于IP选项
  9. iOS_20_微博OAuth授权_取得用户授权的accessToken
  10. Windows环境下IOS APP打包上传AppStore详细流程
  11. Python开发环境-Pyenv安装使用
  12. idea 启动 springBoot debug很慢,正常启动很快是什么原因
  13. 安装并运行Hello World
  14. 使用Angular2的Http发送AJAX请求
  15. android 基础题
  16. test4
  17. Scala使用Akka模拟RPC机制代码2
  18. js调试系列: 控制台命令行API
  19. 进程process与线程thread
  20. IoC Containers with Xamarin

热门文章

  1. 实现分页数据请求的思路/Element UI(Plus)的分页模板(Vue3.x写法),(直接使用<script>引入vue.js)
  2. Guava Retry重试机制
  3. 打包Assetbundle
  4. 杭电 oj 第几天?
  5. 解决PageHelper分页不正常,pages始终等于1,total 始终等于pageSize的问题
  6. flutter-linux(未完成)
  7. memoのQt自动调整窗口尺寸
  8. 【2020NOI.AC省选模拟#2】A. 旋转
  9. Spring Boot 启动时自动执行代码的几种方式
  10. 「NOTE」常系数齐次线性递推