CLOB:JdbcTemplate:c3p0 - 如何重用相同的连接?

时间:2014-08-06 05:30:27

标签: java spring oracle c3p0 clob

我继承了一个具有以下设置的项目:

声明的类和用于执行查询的方法之一如下所示

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的连接?

1 个答案:

答案 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的人来说都可以进行维护。

祝你好运!