我继承了一个具有以下设置的项目:
声明的类和用于执行查询的方法之一如下所示
public class DataSourceServiceImpl extends SimpleJdbcDaoSupport implements DataSourceService {
...
public List<Map<String, Object>> valueList(String dataSource, Object[] params, String sql) throws DataAccessException {
DataSourceContextHolder.setDataSource(dataSource);
return getSimpleJdbcTemplate().getJdbcOperations().queryForList(sql, params);
}
}
示例SQL:
SELECT samplefield FROM sampletable WHERE SDE.ST_INTERSECTS(SHAPE,SDE.ST_GEOMETRY(?,?))= 1 AND SHAPE IS NOT NULL
问题是,如果输入字符串(表示几何)超过了Oracle驱动程序的4000个字符限制,我们就会得到
ORA-01460:请求未执行或无理转换
换句话说,这意味着queryForList(及其背后的任何内容)不会自动处理超出限制的字符串。
经过一番研究,我意识到我必须使用c3p0 OracleUtils来生成一个临时的Clob。所以我修改了代码以检查参数并相应地修改它们:
try {
Connection conn = getConnection();
for (Object obj: params){
if (obj instanceof String && obj.toString().length() > 4000){
Clob clob = OracleUtils.createTemporaryCLOB(conn, true, 10);
clob.setString(1, (String)obj);
clobs.add(clob);
params[i] = clob; // re-assign the parameter back
}
i++;
}
List<Map<String, Object>> result = getSimpleJdbcTemplate().getJdbcOperations().queryForList(sql, params);
if (!clobs.isEmpty())
for (Clob c: clobs) c.free();
} catch (SQLException e) {
e.printStackTrace();
}
不幸的是,这导致了另一个Oracle错误:
ORA-22922:不存在的LOB值
经过另一项研究后,我意识到我指定给“params”参数的临时Clob的指针是空的,很可能是由于“queryForList”在不同的连接中执行(!)比用于生成temporaryClob的那个强。所以我最终得到了以下内容:
JdbcTemplate t = new JdbcTemplate(new SingleConnectionDataSource(conn, false));
result = t.queryForList(sql, params);
哪个有效,但我担心这不是最佳的,只会在将来某个时候引发问题。
我的问题是,有没有办法重用用于为实际查询生成CLOB的连接?
答案 0 :(得分:0)
直截了当的做法是逃避过度复杂的中间件。
public List<Map<String, Object>> valueList(String dataSource, Object[] params, String sql) throws DataAccessException {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
Clob clob = null;
try {
con = dataSource.getConnection();
ps = con.prepareStatement( "SELECT samplefield FROM sampletable WHERE SDE.ST_INTERSECTS(SHAPE, SDE.ST_GEOMETRY(?, ?)) = 1 AND SHAPE IS NOT NULL" ); // probably externalize this SQL string somewhere
// Note that Oracle's two-arg ST_GEOMETRY function takes a CLOB and an INTEGER
// see http://resources.arcgis.com/en/help/main/10.1/index.html#//006z00000050000000
Clob clob = OracleUtils.createTemporaryCLOB(conn, true, 10);
clob.setString(1, (String) params[0]);
ps.setClob( 1, clob );
ps.setObject( 2, params[1], java.sql.Types.INTEGER );
rs = ps.executeQuery();
// inefficient and overdone output format, but hey.
List<Map<String,Object>> out = new LinkedList()
while (rs.next()) {
Map<String,Object> oneBindingMap = new HashMap(1);
oneBindingMap.put("samplefield", rs.getObject(1)); //again, maybe externalize the field name
out.add( oneBindingMap );
}
return out;
}
catch ( SQLException e ) {
throw new DataAccessException( e.getMessage(), e ); // adapt to expected Exception type
}
finally {
try { if ( clob != null ) clob.free(); } catch ( Exception e ) { e.printStackTrace(); }
// in java 7+ you could avoid the rest of this via the try-with-resources construct
try { if ( rs != null ) rs.close(); } catch ( Exception e ) { e.printStackTrace(); }
try { if ( ps != null ) ps.close(); } catch ( Exception e ) { e.printStackTrace(); }
try { if ( con != null ) con.close(); } catch ( Exception e ) { e.printStackTrace(); }
}
}
我只是将其输入网页;我还没有测试它是否编译,并且我对你想要的语义做了一些假设(例如输出映射中的格式和键名)。但我认为这应该会让你非常接近你想要的地方,而不必将你的逻辑卷入其中,以使其适应不打算做你想做的中间件。
或者,我不会发现您的SingleConnectionDataSource黑客有多大错误或可能会失败。它只是让我觉得不透明。我的解决方案更加冗长,但我认为逻辑上非常简单,并且对于任何理解JDBC的人来说都可以进行维护。
祝你好运!