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

Java 多線程註冊併發問題:數據庫連接過早關閉導致後續操作失敗

     編輯:程式設計疑難解答

問題現象

同時註冊兩個用戶,第一個成功,第二個無反應/失敗。錯誤日志顯示數據庫連接已關閉。

代碼邏輯錯誤分析


// 典型錯誤模式
public void register(User user) {
    Connection conn = getConnection(); // 獲取連接
    try {
        // ... 執行 SQL 插入 ...
        conn.close(); // ❌ 在方法內關閉連接!
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

// 併發調用時:
// 線程1: getConnection() → 執行 → close() 連接池歸還/關閉
// 線程2: getConnection() → 可能獲取到已關閉的連接 → 執行失敗

核心原因

  • 連接管理錯誤:在業務方法中手動 close() 連接,導致連接池異常或連接提前歸還
  • 事務邊界不清:註冊應在同一事務中,連接不應在方法中關閉
  • 併發衝突:多線程共享連接池,提前關閉破壞池狀態

正確連接管理模式

方案一:Spring 事務管理 (推薦)


@Service
@Transactional // 方法級事務,Spring 自動管理連接獲取/提交/關閉
public class UserService {
    
    @Autowired
    private UserMapper userMapper; // MyBatis Mapper
    
    public void register(User user) {
        // 無需手動獲取/關閉連接
        userMapper.insert(user); 
        // 異常拋出自動回滾,正常自動提交並歸還連接
    }
}

方案二:手動管理但正確模式 (無 Spring)


public void register(User user) {
    Connection conn = null;
    try {
        conn = dataSource.getConnection(); // 從池獲取
        conn.setAutoCommit(false); // 開啟事務
        
        // 業務操作
        userDao.insert(conn, user);
        
        conn.commit(); // 提交事務
    } catch (SQLException e) {
        if (conn != null) try { conn.rollback(); } catch (SQLException ex) {}
        throw new RuntimeException("註冊失敗", e);
    } finally {
        if (conn != null) try { conn.close(); } catch (SQLException e) {} // 歸還池
    }
}

方案三:連接池配置檢查


# HikariCP 推薦配置
spring.datasource.hikari:
  maximum-pool-size: 20          # 最大連接數
  minimum-idle: 5                # 最小空閒
  connection-timeout: 30000      # 獲取連接超時 30s
  idle-timeout: 600000           # 空閒超時 10min
  max-lifetime: 1800000          # 最大壽命 30min
  connection-test-query: SELECT 1 # 心跳檢查
  validation-timeout: 5000       # 驗證超時

併發註冊的其他陷阱

調試建議

  1. 開啟 SQL 日志:logging.level.org.hibernate.SQL=DEBUG
  2. 監控連接池狀態:HikariCP MBean / Actuator /actuator/metrics/hikaricp.connections.active
  3. 壓測驗證:JMeter 併發 100 線程註冊,觀察成功率與連接池指標

總結

  • 🚫 **業務代碼中不要手動 close 連接** (除非自管理且在 finally 中)
  • ✅ **交給 Spring @Transactional** 或 連接池管理
  • 🔍 **報錯先看日志**:連接已關閉/空指針/超時 90% 是連接管理問題
  • 🛡 **唯一約束在數據庫層**,代碼層捕獲異常轉友好提示
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題現象解決
唯一索引衝突Duplicate entry 'username' for key 'uk_username'捕獲异常返回友好提示、或 INSERT IGNORE/ON DUPLICATE KEY
事務隔離級別幻讀導致重複檢查失效REPEATABLE READ + 唯一索引保證
連接泄漏池耗盡、後續請求卡死finally 必須 close、啟用泄漏檢測