首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

SSH (Struts2+Spring+Hibernate) 併發測試 100 用戶 MySQL 報 Too many connections 解決方案

     編輯:程式設計綜合問答

錯誤堆疊核心

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: 
Data source rejected establishment of connection, message from server: "Too many connections"

明確指出:**MySQL 伺服器拒絕新連線,因達到 max_connections 限制**。

根本原因分析

  1. 未使用連線池:預設 `DriverManagerConnectionProvider` 每次請求建立新連線,不重用,極易耗盡資源。
  2. 連線未正確關閉:DAO/Service 層異常流程未在 `finally` 區塊關閉 Session/Connection,導致洩漏。
  3. MySQL 預設 max_connections 過小:預設 151,併發 100 且連線不釋放即觸頂。
  4. Hibernate 設定不當:`hibernate.connection.release_mode` 預設 `auto` (交易結束釋放),若交易管理失效則不釋放。

解決方案 (按優先序)

1. 必須引入高效能連線池 — C3P0 / DBCP2 / HikariCP (強烈推薦 HikariCP)

Spring XML 配置 HikariCP 範例:

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&useSSL=false" />
    <property name="username" value="root" />
    <property name="password" value="password" />
    <!-- 核心池大小:CPU 核心數 * 2 + 1 (建議 20-50) -->
    <property name="maximumPoolSize" value="30" />
    <!-- 最小閒置連線 -->
    <property name="minimumIdle" value="10" />
    <!-- 連線超時 (毫秒) -->
    <property name="connectionTimeout" value="30000" />
    <!-- 空閒超時 -->
    <property name="idleTimeout" value="600000" />
    <!-- 最大生命週期 -->
    <property name="maxLifetime" value="1800000" />
    <!-- 連線測試查詢 -->
    <property name="connectionTestQuery" value="SELECT 1" />
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <!-- 其他屬性 -->
</bean>

2. 調整 MySQL `max_connections`

-- 臨時生效 (重啟失效)
SET GLOBAL max_connections = 500;

-- 永久生效 (my.cnf / my.ini)
[mysqld]
max_connections = 500
open_files_limit = 65535  -- 配合調大

注意:盲目調大 `max_connections` 而無連線池,會導致記憶體耗盡 (每連線約 2-10MB)。**連線池是治本,調參數是治標**。

3. 修正 Hibernate 連線釋放模式

<property name="hibernate.connection.release_mode">after_transaction</property>

確保 `@Transactional` 正確配置,交易邊界清晰,Session 隨交易關閉歸還連線池。

4. 程式碼層面檢查 — 杜絕連線洩漏

  • DAO 使用 `HibernateTemplate` 或 `sessionFactory.getCurrentSession()`,**不要**手動 `openSession()`/`close()`。
  • 若必須手動管理,務必 `try { ... } finally { session.close(); }`。
  • 避免在循環中開啟交易,批次操作用 `session.flush()`/`clear()` 並單一交易提交。

5. 優化 SQL 與索引 — 降低連線佔用時間

  • 慢查詢導致連線長期佔用,EXPLAIN 分析、加索引、避免全表掃描。
  • 啟用 Hibernate 二級快取 (Ehcache/Redis) 減少重複查詢。

驗證步驟

  1. 啟用連線池監控 (HikariCP 支援 JMX/Micrometer/Prometheus)。
  2. 壓測觀察 `ActiveConnections`、`IdleConnections`、`ThreadsAwaitingConnection` 指標。
  3. 確認峰值併發下連線池未耗盡、無 `PoolExhaustedException`、MySQL `Threads_connected` 穩定。

結論

**「Too many connections」核心對策:上連線池 (HikariCP) + 合理設定池大小 + 修正交易管理 + 優化 SQL**。單靠調大 MySQL `max_connections` 是自欺欺人,終將導致 OOM。建立完善的連線池監控與壓測機制,才能保證生產環境穩定。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved