本文来自李明子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”均应作为方法参数以最大化重用代码。在实际的代码中,我们也是这样封装的。