某 Java 系統每日午夜定時任務:調用外部 REST API 獲取數據 → 解析入庫(雙節點去重插入),初始版本單線程、頻繁建連、Statement 拼接 SQL、逐條執行、日志噪音大,**總耗時 ~100 秒**,目標 < 60 秒。
| 優化點 | 手段 | 耗時 | 提升 |
|---|---|---|---|
| 1. 日志降噪 | 調整 java.util.logging 級別至 SEVERE,屏蔽重複鍵異常 | 50s | 50% |
| 2. 連接復用 | 單例模式共享 Connection,避免 5 次重建開銷 | 40s | 20% |
| 3. 預編譯 SQL | PreparedStatement 替代 Statement,DB 緩存執行計劃 | 30-35s | ~15% |
| 4. 批處理插入 | addBatch() + executeBatch(),網絡往返從 N 次降為 1 次 | 30s | 微幅 |
| 5. 多線程並行 | 清表/雙節點入庫拆分為 3 任務,4 核 CPU 並行執行 | 10-15s | 50%+ |
| 6. DAO 分層 | 抽象 DeviceDAO 接口,業務與數據訪問解耦 | 10-15s | 無性能增益,但可維護性質變 |
Java I/O 遠慢於 C/C++,千條重複鍵異常日志導致大量磁盤寫入與格式化開銷。生產環境建議:非核心路徑禁用 DEBUG/INFO,採用異步日志框架(Logback/Log4j2 AsyncAppender)。
本場景屬低併發批量任務,單例共享連接足夠;高併發 Web 應用必須使用 HikariCP 等成熟連接池,配置 maximumPoolSize、connectionTimeout 等參數。
預編譯減少 DB 解析優化器開銷;批處理將 N 次網絡 RTT 合併為 1 次,對跨機房部署效果尤為明顯。注意:executeBatch() 返回 int[] 需檢查每條執行結果,異常時回滾策略需配合事務管理器。
任務拆分:清表(串行前置)→ 節點 A 入庫 → 節點 B 入庫(並行)。Thread.join() 保證順序。實測 3 線程最優,6 線程反而變慢(上下文切換開銷 > 並行收益),**線程數 ≈ CPU 核心數** 為經驗基準。
引入 DeviceDAO 接口 + DeviceDAOImpl 實現,上層依賴抽象,支援多數據庫切換、單元測試 Mock,符合「開閉原則」與「依賴倒置」。