sql执行阶段不发生握手,握手仅发生在连接建立时;必须用连接池复用连接来避免重复握手,select 1验证不可省略,否则网络设备静默断连会导致偶发通信失败,且需协同调优wait_timeout与maxlifetime等参数。

直接结论:SQL执行阶段本身不发生MySQL握手,握手只发生在连接建立时;所谓“优化SQL执行阶段的握手开销”,本质是避免在每次SQL执行前新建连接——必须靠连接池复用连接来解决,而非调整SQL层参数。
为什么SELECT 1验证不能省略?
很多团队为“减少开销”把testOnBorrow关掉,结果上线后偶发Communications link failure或Connection reset。这是因为MySQL服务端默认wait_timeout=28800(8小时),但中间网络设备(如NAT网关、云负载均衡)可能5–15分钟就静默断连。连接池里“看着空闲”的连接,实际已失效。不验证就直接交给业务线程执行SQL,第一次executeQuery()就会触发重连+握手,反而放大延迟。
- 必须开启
testOnBorrow或testWhileIdle,配合validationQuery=SELECT 1 - HikariCP中改用
connectionTestQuery=SELECT 1(注意不是validationQuery) - Druid中保持
validationQuery=SELECT 1,并确保testOnBorrow=true - 避免用
mysql_ping():它不是标准SQL,部分代理(如ProxySQL)不支持,且JDBC驱动未统一实现
maxLifetime和wait_timeout必须协同设置
如果连接池允许连接存活太久,而MySQL服务端早把它踢了,就会出现“连接池认为还活着,MySQL认为已关闭”的状态错配。典型现象是偶发Invalid MySQL connection或查询卡住数秒后失败。
- 设
maxLifetime比MySQL的wait_timeout小至少60秒,例如MySQL设wait_timeout=300,连接池就设maxLifetime=240000(4分钟) - 同时调低
idleTimeout(如300000,5分钟),让长期不用的连接主动归还,避免堆积无效连接 - 不要依赖
autoReconnect=true:MySQL JDBC驱动已标记该参数为deprecated,且无法处理事务上下文丢失问题
连接池大小与SQL并发模式强相关
很多人按QPS×响应时间粗算连接数,却忽略SQL执行是否串行阻塞。比如一个HTTP请求内顺序执行5条SQL,每条耗时20ms,总耗时100ms——它只占用1个连接100ms,而不是5个连接各20ms。错误估算会导致连接池过大,挤占MySQLmax_connections资源。
- 真实连接需求 = 并发请求数 × 单请求最大**同时持有**连接数(注意是“同时”,不是“累计”)
- ORM场景下,
@Transactional方法内所有SQL共享同一连接;异步调用(如CompletableFuture)才可能跨连接 - 最大连接数建议 ≤ MySQL
max_connections× 0.7,例如MySQL设max_connections=500,连接池maximumPoolSize最多设350 - 最小空闲连接
minimumIdle设为最大值的20%~30%,防止突发流量时频繁创建新连接(每次创建都触发完整握手)
真正容易被忽略的点是:连接池参数调优必须和MySQL服务端参数一起看,单独调连接池就像只换轮胎不调刹车。尤其wait_timeout、max_connections、thread_cache_size这三个值,任何一项不匹配,都会让连接池“复用”变成“假复用”,握手开销照旧打满。











