mysql SQLNonTransientConnectionException 异常分析处理

问题描述:

线上某个业务在运行时突然抛出这么一个异常信息:

java.sql.SQLNonTransientConnectionException: (conn=328473) unexpected end of stream, read 0 bytes from 4 (socket was closed by server)
at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.get(ExceptionMapper.java:240)
at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.getException(ExceptionMapper.java:171)
at org.mariadb.jdbc.MariaDbStatement.executeExceptionEpilogue(MariaDbStatement.java:248)
at org.mariadb.jdbc.ClientSidePreparedStatement.executeInternal(ClientSidePreparedStatement.java:230)
at org.mariadb.jdbc.ClientSidePreparedStatement.execute(ClientSidePreparedStatement.java:157)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:198)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:198)


原因分析:

【1】线上某个操作突然抛出这个异常,因为之前没出现过,首先第一反应是不是网络抖动问题导致的超时而衍生出的问题.

【2】把数据库的连接都改为了内网访问,发现还是会出现。
【3】怀疑是连接池配置问题,怀疑是不是从连接池中获取到的连接有问题,于是改了连接池的 test-on-borrow: true (从池中取连接时校验当前链接是否可用)、
test-on-return: true (把连接放回池中时校验是否可用)、 test-while-idle: true (开启验证连接的有效性) ,time-between-eviction-runs-millis: 6000 (空闲连接的回收间隔时间 ,这个与test-while-idle搭配使用,即每隔6秒钟把空闲的连接进行回收) 。通过这一步,确保连接池的连接是可用的。发现还是出现这个异常。
【4】叫开发人员去看看这一块的业务逻辑,发现有个大事务的操作。
【5】最后还是锁定在SQLNonTransientConnectionException 这个异常上。然后查看了一下数据库中的一些参数配置,然后发现了这么个东东:innodb_lock_wait_timeout , 默认值为 50秒 , 意思是一旦数据库锁超过这个时间,就会报错。
在这里插入图片描述

【6】再把日志文件拿下来,查看了一下这个带事务的业务逻辑执行完的一个时间跨度,发现执行了60多秒(里面有一些发消息的动作,都是用同步操作,还有一些sleep睡眠时间,,所以在执行最后一个update操作的时候,这个事务(锁)占用的时间已经是超过了innodb_lock_wait_timeout指定的50秒)
【7】校验重现问题:在备环境中减少这个业务逻辑的步骤,比如之前出问题是6个步骤,现在改成3-4个 , 执行测试,50秒内执行完成,后台也不会报错,正常。然后再把步骤增加到5-6个以上,发现都需要在50+秒以上才执行完,也是在最后一个update要执行时抛出这个异常。


解决方案:

改代码,把一些业务外的弄成异步,优化执行的sql , 更新上线,over~

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MySQL 中,可以使用异常处理处理存储过程中的异常情况。MySQL 提供了两种类型的异常:条件异常SQLSTATE 异常。 条件异常是基于条件的自定义异常,在存储过程中使用 SIGNAL 语句来抛出异常。下面是一个示例: ```sql CREATE PROCEDURE example_procedure() BEGIN DECLARE custom_error CONDITION FOR SQLSTATE '45000'; DECLARE EXIT HANDLER FOR custom_error BEGIN -- 异常处理逻辑 -- 可以使用 GET DIAGNOSTICS 语句获取异常信息 GET DIAGNOSTICS CONDITION 1 @sql_state = RETURNED_SQLSTATE, @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT; -- 输出异常信息 SELECT CONCAT('Error: ', @text) AS ErrorMessage; END; -- 抛出异常 SIGNAL custom_error SET MESSAGE_TEXT = 'Custom error message'; END; ``` 在上面的示例中,我们创建了一个名为 `example_procedure` 的存储过程。在存储过程中,我们定义了一个名为 `custom_error` 的条件异常。然后,我们使用 `DECLARE EXIT HANDLER FOR custom_error` 语句来指定当 `custom_error` 异常被抛出时要执行的处理程序。在处理程序中,我们使用 `GET DIAGNOSTICS` 语句获取异常信息,并输出异常信息。 另一种类型的异常SQLSTATE 异常,它是基于 MySQL 错误代码的系统定义异常。当出现预定义的错误代码时,MySQL 会自动抛出异常。可以使用 `DECLARE ... HANDLER FOR SQLEXCEPTION` 或 `DECLARE ... HANDLER FOR SQLWARNING` 语句来指定异常处理程序。 下面是一个使用 SQLSTATE 异常处理的示例: ```sql CREATE PROCEDURE example_procedure() BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN -- 异常处理逻辑 SELECT CONCAT('Error: ', SQLSTATE) AS ErrorMessage; END; -- 引发异常 SELECT 1 / 0; END; ``` 在这个例子中,我们创建了一个名为 `example_procedure` 的存储过程。我们使用 `DECLARE EXIT HANDLER FOR SQLEXCEPTION` 语句指定当发生任何异常时要执行的处理程序。在处理程序中,我们使用 `SQLSTATE` 函数获取异常SQLSTATE 值,并输出异常信息。 这些都是处理 MySQL 存储过程中异常情况的一些基本方法。你可以根据实际需求来选择适当的处理方式和异常类型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值