CLOB: JdbcTemplate: c3p0 - как повторно использовать то же соединение?

1

Я унаследовал проект, который имеет следующую настройку:

  • весенний каркас: 3.2.2
  • драйверы oracle: ojdbc6.jar: 11.2.0.4
  • c3p0 для объединения пулов: 0.9.1.2
  • он использует динамическую маршрутизацию источника данных, вдохновленную мной в этой статье http://spring.io/blog/2007/01/23/dynamic-datasource-routing/

Объявленный класс и один из методов, используемых для выполнения запросов, выглядят следующим образом:

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 И ФОРМА НЕ НЕТ

Проблема в том, что если входная строка (представляющая геометрию) превышает предел символов Oracle 4000, мы получаем

ORA-01460: запрошенная неоплаченная или необоснованная конверсия

Другими словами, это означает, что queryForList (и все, что стоит за ним) не обрабатывает строки, превышающие лимит.

После некоторых исследований я понял, что для создания временного Clob я должен использовать Oracle3t0 cdp0. Поэтому я изменил код, чтобы проверить параметры и соответственно изменить их:

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

После другого исследования я понял, что указатель на временный Clob, который я присвоил параметру "params", пуст и, скорее всего, из-за того, что "queryForList" выполняется в другом соединении (!), Чем тот, который используется для генерируя временный список. Поэтому я получил следующее:

JdbcTemplate t = new JdbcTemplate(new SingleConnectionDataSource(conn, false));
result = t.queryForList(sql, params);

который работал, но я боюсь, что это не оптимально и будет только вызывать проблемы в какой-то момент в будущем.

Мой вопрос в том, есть ли способ повторно использовать соединение, используемое для генерации CLOB для фактического запроса?

Теги:
spring
clob
c3p0

1 ответ

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 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.

Удачи!

  • 0
    Спасибо за ответ, у меня было это решение раньше (с подготовленным состоянием), но я действительно не хотел связываться с результирующим набором, хотел сохранить его в чистоте (несмотря на беспорядок, с которым я закончил), хотя спасибо за карту привязки: ). Тем не менее, есть ли способ указать jdbctemplate в операции запроса использовать соединение, которое у меня уже есть? Или какая-нибудь обстановка где-нибудь, которая сделала бы все это для меня? .. так же, как раньше было SetBigStringTryClob или что-то подобное ...

Ещё вопросы

Сообщество Overcoder
Наверх
Меню