本文來自李明子csdn部落格(http://blog.csdn.net/free1985),商業轉載請聯絡博主獲得授權,非商業轉載請註明出處。
摘要:本文簡述了Oracle資料庫報ORA-01795異常的解決方案,並提供了可以直接使用的原始碼供讀者參考。 1 問題描述
在許多基於關聯式資料庫開發的管理系統中會用到動態sql。即在java代碼中根據業務語義動態拼接sql語句,執行後得到對應結果集或實現對錶的操作。
對於使用Oracle資料庫的系統,如果我們在拼接where in時,其item的個數超過1000,在sql執行時會拋出ORA-01795異常。該異常的描述如下:
如果業務系統開放了使用者建模、業務配置等功能,在進行了某些“不可思議”的配置後該現象是很可能出現的。當然,對於大量操作和檢查則更容易出現這個問題。 2 解決問題的基礎方式
解決該問題的基礎方式是將原sql語句轉換為等價的對Oracle合法的sql語句。對於where column in (A,B,C,D……) 這樣的語句,where column in (A,B……) or column in(C,D……)是完全等價的。我們需要做的只是將item按照每1000個一組進行分組。
下面給出實現代碼。
/** * 擷取where in語句 * * @param column 欄位名 * @param values 值集合 * @return where in語句 */ private String GetWhereInValuesSql(String column, List<String> values) { // sql語句 String sql = "("; // 值的個數 int valueSize = values.size(); // 批次數 int batchSize = valueSize / 1000 + (valueSize % 1000 == 0 ? 0 : 1); for (int i = 0; i < batchSize; i++) { if (i > 0) { sql += ") or "; } sql += column+" in ("; for (int j = i * 1000; ( j < (i + 1) * 1000) && j < valueSize; j++) { if (j > i * 1000) { sql += ","; } sql += "'" + values.get(j) + "'"; } } sql += "))"; return sql; }
3 解決問題的進階方式
如果where in語句中的item數量巨大,則應該進一步使用批量提交。比如在TiEAF中,我們為在JDBC基礎上封裝的資料庫訪問類添加了處理where in的批量擷取和批次更新方法。其原理是: 根據每批尋找量產生sql,資料部分使用預留位置; 使用二維數組對要尋找的item整組的資料(可整除部分)進行分組,作為綁定參數; 執行批量查詢; 對求模運算的餘數部分編寫單獨的sql語句,資料部分使用預留位置; 將剩餘item資料群組織成參數數組; 執行單查詢; 合并、返回結果;
鑒於保密問題,該部分無法提供源碼,請讀者見諒。 4 擴充
4.1 where not in
對於where column ont in (A,B,C,D……) 這樣的語句,與其等價的是where column not in (A,B……) and column not in(C,D……)。
4.2 封裝形式
在實際代碼中,每批的item數、“where in或where not in”均應作為方法參數以最大化重用代碼。在實際的代碼中,我們也是這樣封裝的。