Spring Boot环境下@Transactional注解的MySQL socket超时行为差异咨询
基础前提:socketTimeout参数的作用
你在JDBC URL中配置的socketTimeout=10000,是MySQL驱动给每条TCP连接设置的SO_TIMEOUT属性,只作用于单次网络IO操作的等待时长:当你向MySQL发送SQL后,等待服务端返回响应的时间如果超过10秒,驱动会直接断开连接,抛出通信链路失败异常。这个参数不对空闲连接的闲置时长做限制。
代码1触发异常的原因
带@Transactional注解的方法执行时,Spring事务管理器会先从DBCP2连接池获取一条数据库连接,绑定到当前线程,直到方法执行结束才会归还连接。
代码1中拿到连接后直接执行SELECT sleep(12):该SQL发送到MySQL服务端后,需要12秒才能执行完成返回结果,触发了10秒的socketTimeout限制,驱动主动断开连接,抛出你看到的异常。后续事务尝试回滚时,连接已经失效,因此额外出现了Application exception overridden by rollback exception的报错。
代码2正常运行的原因
代码2进入方法后同样先获取事务连接,然后执行Thread.sleep(12000):这段时间是Java进程本地休眠,持有连接处于空闲状态,没有正在等待响应的SQL请求,因此不会触发socketTimeout规则。
同时MySQL服务端默认的连接闲置超时参数wait_timeout为8小时,远大于12秒,服务端不会主动断开这条空闲连接。12秒休眠结束后执行的SELECT count(*) from my_table执行耗时极短,远小于10秒的socketTimeout限制,因此可以正常拿到结果返回。
补充说明
你配置的autoReconnect=true不会在代码1的场景生效:该参数仅在发起新SQL请求时检测到连接失效才会尝试重连,代码1是SQL已经发送、等待响应过程中超时断开,不会触发重连逻辑,直接抛出异常。
内容的提问来源于stack exchange,提问作者Aman Rawat

