☰
MyBatis连接池配置优化与支付订单丢失问题解决
2026/10/15 9:50:27 网站建设 项目流程

1. 问题现象:支付成功但订单消失的诡异现象

上周五晚上10点23分,我正在悠闲地喝着咖啡检查生产环境日志,突然收到一连串用户投诉:"明明显示支付成功了,为什么订单列表里找不到?"。作为一个有五年电商系统开发经验的老手,我立刻意识到这不是普通的偶发问题。

通过查询支付网关回调记录,确认这些订单确实完成了第三方支付,金额也已经扣除。但诡异的是,订单表里就是找不到对应的记录。更令人不安的是,这种现象只出现在高峰期(晚8点-11点),白天完全正常。

2. 问题排查:从表象到根源的侦探之旅

2.1 初步排查方向

首先我排除了最明显的可能性:

  • 支付回调处理逻辑:日志显示回调处理正常完成
  • 事务回滚:没有异常日志,且支付成功不应该回滚
  • 缓存不一致:直接查库也不存在记录

2.2 关键线索发现

在仔细比对日志时,我发现一个奇怪的时间差:支付回调处理完成时间与订单创建时间存在约8秒间隔。而我们的支付处理逻辑应该是同步完成的。

进一步检查发现,这8秒期间有数据库连接获取超时的警告日志。这让我把怀疑目光投向了数据库连接池。

3. MyBatis连接池深度解析

3.1 连接池配置现状

我们使用的是MyBatis默认的HikariCP连接池,配置如下:

spring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.connection-timeout=3000 spring.datasource.hikari.idle-timeout=60000

3.2 连接池工作原理

HikariCP的工作流程可以类比为图书馆借书:

  1. 应用线程像读者一样请求连接(借书)
  2. 连接池像图书馆管理员,有空闲连接就直接分配
  3. 没有空闲时,要么等待(不超过connection-timeout),要么新建连接(不超过maximum-pool-size)

3.3 问题根因分析

在高峰期,我们的服务出现了以下情况:

  1. 并发请求突增导致连接池耗尽
  2. 新连接创建需要时间(平均2秒)
  3. 支付回调线程等待3秒后超时放弃
  4. 但支付网关已经扣款,导致数据不一致

4. 解决方案设计与实施

4.1 短期应急措施

立即采取的临时方案:

// 在支付回调处理中增加重试机制 @Transactional public void handlePaymentCallback(PaymentInfo info) { int retry = 0; while (retry < 3) { try { // 业务处理逻辑 return; } catch (CannotGetJdbcConnectionException e) { retry++; Thread.sleep(1000); } } // 记录补偿任务 }

4.2 长期优化方案

经过压力测试后,我们调整了连接池配置:

# 根据实际并发量调整 spring.datasource.hikari.maximum-pool-size=50 spring.datasource.hikari.connection-timeout=5000 # 新增最小空闲连接 spring.datasource.hikari.minimum-idle=10 # 添加连接健康检查 spring.datasource.hikari.connection-test-query=SELECT 1

4.3 架构层面改进

  1. 引入熔断机制:当连接池使用率超过90%时,快速失败并降级
  2. 实现异步订单补偿:通过消息队列确保最终一致性
  3. 增加监控告警:对连接池使用率设置阈值告警

5. 生产环境验证与效果

5.1 压测对比数据

指标优化前优化后
最大TPS120350
平均响应时间1.2s280ms
错误率8.7%0.02%

5.2 实际业务影响

优化上线后:

  • 订单丢失投诉降为零
  • 高峰期系统稳定性显著提升
  • 数据库连接数更加平稳,避免了剧烈波动

6. 经验总结与避坑指南

6.1 连接池配置黄金法则

  1. maximum-pool-size不是越大越好,建议公式:

    合理最大值 = (核心数 * 2) + 有效磁盘数

    我们16核服务器最终设置为50

  2. connection-timeout应该大于平均查询耗时,但不超过用户可忍受时间

  3. 一定要设置minimum-idle,避免突发流量冲击

6.2 监控指标 checklist

必须监控的关键指标:

  • 活跃连接数
  • 空闲连接数
  • 等待获取连接的线程数
  • 连接获取平均耗时

6.3 其他常见陷阱

  1. 不同框架的默认配置差异:

    • HikariCP默认maxPoolSize是10
    • Tomcat JDBC默认maxActive是100
  2. 事务超时与连接超时的区别:

    • 事务超时是整个事务的时限
    • 连接超时是获取连接的等待时间
  3. 连接泄漏检测:

    spring.datasource.hikari.leak-detection-threshold=60000

7. 进阶思考:分布式事务的考量

对于支付这类敏感操作,我们后来引入了Saga模式:

  1. 支付成功即创建订单(状态为处理中)
  2. 异步执行库存扣减等操作
  3. 任何步骤失败触发补偿流程

这种模式虽然复杂,但彻底解决了这类一致性问题。不过实施成本较高,需要根据业务重要性权衡。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询