當使用 Hibernate 處理超過萬筆資料的批次寫入時,若不加控制,Session 一級快取會累積大量實體導致 OutOfMemoryError。官方參考文件建議採用 批次處理 + 定期 flush/clear 模式。
hibernate.jdbc.batch_size(如 50)啟用 JDBC 批次更新。session.flush() 送資料庫,再呼叫 session.clear() 清空一級快取。public boolean insertBatch(final Object objPO) {
boolean isSuccess = false;
Transaction tx = null;
Session session = openSession();
try {
tx = session.beginTransaction();
for (int i = 0; i < 100_000; i++) {
session.save(objPO);
// 每 50 筆 flush + clear
if (i % 50 == 0) {
session.flush();
session.clear();
}
}
tx.commit();
isSuccess = true;
} catch (HibernateException ex) {
if (tx != null) {
try { tx.rollback(); } catch (HibernateException ignored) {}
}
log.error("Batch insert failed", ex);
} finally {
session.close();
}
return isSuccess;
}
實務專案常需更精細控制:
// 1. 利用 HibernateDaoSupport 開啟新 Session(不受 Spring 交易管理)
public Session openSession() {
return getHibernateTemplate().getSessionFactory().openSession();
}
// 2. 業務邏輯:自行控制 flush/clear
protected void doBusiness(Session session) {
while (hasMoreData()) {
processBatch(session); // 你的批次處理邏輯
session.flush();
session.clear();
log.info("Batch committed");
}
}
// 3. 呼叫端:開啟 Session → 處理 → 關閉
Session session = openSession();
try {
doBusiness(session);
} finally {
session.close(); // 必須關閉,否則連線洩漏
}
sessionFactory.openStatelessSession() 完全繞過一級快取,適合純大量匯入,但失去級聯儲存、延遲載入等功能。identity 策略(無法批次),改用 sequence 或 enhanced-sequence。innodb_buffer_pool_size、wal_buffers 等參數。clear() 導致記憶體暴增掌握「分批、flush、clear」三部曲,配合資料庫參數調優,Hibernate 也能輕鬆應付百萬級資料匯入。