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

Hibernate hbm2ddl.auto=update 報錯排查:Schema 更新衝突與資料庫連接池耗盡

     編輯:程式設計疑難解答

現象

  • hbm2ddl.auto=create 正常,改為 update 即報錯(但仍能執行)。
  • 第二天資料庫報 10061(連接被拒絕/連接池耗盡)。

可能原因

  1. Schema 更新衝突: update 嘗試比對實體與資料庫結構,若實體註解(@Column, @Table)與現有表結構不一致(型別、長度、預設值、外鍵),Hibernate 可能執行 ALTER TABLE 失敗、鎖表、或產生無效 DDL,導致後續 Session 建立失敗。
  2. Session/Transaction 洩漏: 代碼中 session.close()、sessionFactory.close() 僅在 @After 呼叫,若測試方法拋出異常、@After 未執行,Session 不會關閉,連接不歸還池中,累積導致連接池耗盡(10061)。
  3. 資料庫鎖未釋放: update 執行 DDL 時可能持有元資料鎖,若事務未提交/回滾,鎖持有至連接關閉,並發測試時互相阻塞。
  4. MySQL wait_timeout 過短: 連接池閒置連接被 MySQL 主動斷開,Hibernate 未驗證連接有效性(validationQuery),再用時拋錯。

排查步驟

  1. 啟用 SQL 日誌與 DDL 記錄:
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>
    <property name="hibernate.generate_statistics">true</property>
    
    觀察 update 產生的 ALTER TABLE 是否報錯。
  2. 檢查連接池配置(C3P0/HikariCP):
    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">20</property>
    <property name="hibernate.c3p0.timeout">300</property>          
    <property name="hibernate.c3p0.idle_test_period">300</property>  
    <property name="hibernate.c3p0.preferredTestQuery">SELECT 1</property>
    
    或 HikariCP:
    <property name="hibernate.hikari.maximumPoolSize">20</property>
    <property name="hibernate.hikari.idleTimeout">300000</property>
    <property name="hibernate.hikari.connectionTestQuery">SELECT 1</property>
    
  3. 改用 validate 模式驗證: hbm2ddl.auto=validate 僅檢查一致性,**不修改資料庫**,適合生產/測試環境。開發階段用 update,但需配合資料庫遷移工具(Flyway/Liquibase)管理 Schema 版本。
  4. 確保 Session 必關閉: 用 try-with-resources (Java 7+) 或 finally 區塊保證 session.close() 執行。

代碼修正範例

@Test
public void testSaveStudents() {
    Session session = null;
    Transaction tx = null;
    try {
        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        Students s = new Students();
        s.setSname("POLY Ma");
        // ... set other fields
        session.save(s);
        tx.commit();
    } catch (Exception e) {
        if (tx != null) tx.rollback();
        throw e;
    } finally {
        if (session != null) session.close();  // 必須關閉
    }
}

最佳實踐總結

  • **開發/測試用 update,生產嚴禁**——改用 Flyway/Liquibase 版本化遷移。
  • **連接池必配驗證查詢、閒置超時回收**,防止死連累積。
  • **Session/Transaction 嚴格配對關閉**,用 try-finally 或 Spring @Transactional 管理。
  • **實體註解與資料庫結構保持同步**,避免 update 產生危險 DDL。

參考: CSDN 相關文章

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