java當中的批處理

mgoann發表於2020-04-06

在對資料庫進行批量操作時,應分析操作的前後相關性,如果屬於大批量的操作,而且前續操作的結果不依賴與後繼操作,則完全可以使用批處理來操作DB

使用批處理的優點:

1.        多個SQL語句的執行,共用一個Connection資源。在對資料庫操作時,connection資源是很寶貴的,資料庫的維護從某種角度來說,就是減少資料庫的連線數,減輕對DB的壓力。建立一個資料連線要遠遠比使用資料庫連線消耗資源。這也正是資料庫連線池存在的意義。

public void updateStateBactch(List elms) { 
Connection conn = null; 
PreparedStatement ps = null; 
String sql = "update test_table set state=? where keyid = ?"; 

conn = DBTools.getConnection(); 

if(conn == null) 
{ 
log.error("[update][state][error][conn is null]"); 
return; 
} 

try { 
ps = conn.prepareStatement(sql); 
for(int i = 0; i < elms.size(); i++) { 
Element elm = (Element) elms.get(i); 
if(null == elm || null == elm.getUserId() 
|| null == elm.getState()) { 
continue; 
} 
ps.setInt(1, elm.getStatus()); 
ps.setString(2, elm.getProcID()); 
ps.addBatch(); 
} 
ps.executeBatch(); 
ps.clearBatch(); 
} catch (SQLException sqlEx) { 
log.warn("[update][state][error][SQLException]"); 
} catch (Exception e) { 
log.warn("[update][state][error][SQLException]"); 
} finally { 
DBTools.close(conn, ps, null); 
} 
} 

 

try { 
ps = conn.prepareStatement(sql); 
for(int i = 0; i < elms.size(); i++) { 
Element elm = (Element) elms.get(i); 
if(null == elm || null == elm.getUserId() 
|| null == elm.getState()) { 
continue; 
} 
ps.setInt(1, elm.getStatus()); 
ps.setString(2, elm.getProcID()); 
ps.addBatch(); 
if ((i != 0 && i % 2000 == 0) || i == elms.size() - 1) { 
ps.executeBatch(); 
ps.clearBatch(); 
ps.close(); 
ps = conn.prepareStatement(sql); 
} 
} 
} catch (SQLException sqlEx) { 
log.warn("[update][state][error][SQLException]"); 
log.warn(sqlEx); 
} catch (Exception e) { 
log.warn("[update][state][error][SQLException]"); 
log.warn(e); 
} finally { 
DBTools.close(conn, ps, null); 
} 

 

2. 使用批處理時,沒有關注DB測異常情況,導致批處理失敗。這裡涉及到一些異常處理最基本的點。上述例程還有個小小的問題需要注意,當ps.executeBatch()執行時,如果該批次的SQL語句中有一條SQL丟擲異常,那麼後續的批處理將不會有執行的機會,導致漏執行。所以經過優化後:

try { 
ps = conn.prepareStatement(sql); 
for(int i = 0; i < elms.size(); i++) { 
try { 
Element elm = (Element) elms.get(i); 
if(null == elm || null == elm.getUserId() 
|| null == elm.getState()) { 
continue; 
} 
ps.setInt(1, elm.getStatus()); 
ps.setString(2, elm.getProcID()); 
ps.addBatch(); 
if ((i != 0 && i % 2000 == 0) || i == elms.size() - 1) { 
ps.executeBatch(); 
ps.clearBatch(); 
ps.close(); 
ps = conn.prepareStatement(sql); 
} 
} catch (SQLException e) { 
log.warn("[update][state][error][SQLException]"); 
log.warn(e); 
ps.clearBatch(); 
ps.close(); 
ps = conn.prepareStatement(sql); 
} catch (Exception e) { 
log.warn("[update][state][error][SQLException]"); 
log.warn(e); 
ps.executeBatch(); 
ps.clearBatch(); 
ps.close(); 
ps = conn.prepareStatement(sql); 
} 

} 
} catch (SQLException sqlEx) { 
log.warn("[update][state][error][SQLException]"); 
log.warn(sqlEx); 
} catch (Exception e) { 
log.warn("[update][state][error][SQLException]"); 
log.warn(e); 
} finally { 
DBTools.close(conn, ps, null); 
} 

 

3. 使用批處理時,當批處理中有一條SQL語句優化SQL異常而導致整個批處理失敗。在列印日誌時應該注意,以上的列印方式對問題定位沒有任何幫助。如上如果其中的一條SQL語句執行失敗,那麼你不知道究竟是什麼異常,因為沒有列印異常列,而只列印了最頂層異常。例如:如上程式在DB2資料庫中執行失敗後,只返回瞭如下資訊com.ibm.db2.jcc.c.vd: Non-atomic batch failure.  The batch was submitted, but at least one exception occurred on an individual member of the batch. Use getNextException() to retrieve the exceptions for specific batched elements.大概意思是批處理執行失敗,批處理已經提交,但是其中至少有一條或者多條執行失敗。使用getNextException來檢視執行白失敗的SQL語句異常資訊,便於定位!可是這樣還是有問題,你知道了SQL語句的異常了,但是你不知道究竟是那條SQL語句導致的異常,其實可以更具批處理執行的返回值來檢查執行結果。

Int[] results = ps.executeBatch();

相關文章