Использование подготовленных операторов с JDBCTemplate - PullRequest
26 голосов
/ 07 июня 2010

Я использую шаблон JDBC и хочу читать из базы данных, используя подготовленные операторы. Я перебираю много строк в файле .csv, и в каждой строке я выполняю несколько запросов выбора SQL с соответствующими значениями.

Я хочу ускорить чтение из базы данных, но я не знаю, как заставить шаблон JDBC работать с подготовленными утверждениями.

Существует PreparedStatementCreator и PreparedStatementSetter . Как и в этом примере , оба они созданы с помощью анонимных внутренних классов. Но внутри класса PreparedStatementSetter у меня нет доступа к значениям, которые я хочу установить в подготовленном выражении.

Поскольку я перебираю файл .csv, я не могу жестко закодировать их как строку, потому что я их не знаю. Я также не могу передать их в PreparedStatementSetter, потому что нет аргументов для конструктора. И установка моих значений в final тоже будет глупой.

Я привык к тому, что готовые заявления были довольно простыми. Что-то вроде

PreparedStatement updateSales = con.prepareStatement(
    "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75); 
updateSales.setString(2, "Colombian"); 
updateSales.executeUpdate():

как в этом руководстве по Java .

Ответы [ 5 ]

28 голосов
/ 07 июня 2010

По умолчанию JDBCTemplate делает свой собственный PreparedStatement внутри, если вы просто используете форму .update(String sql, Object ... args).Spring и ваша база данных будут управлять скомпилированным запросом за вас, поэтому вам не нужно беспокоиться об открытии, закрытии, защите ресурсов и т. Д. Одно из преимуществ Spring. Ссылка на документацию Spring 2.5 по этому вопросу. Надеюсь, это прояснит ситуацию.Кроме того, кэширование операторов может быть выполнено на уровне JDBC, как в случае по крайней мере с некоторыми драйверами Oracle JDBC. Это будет более подробно, чем я могу компетентно.

19 голосов
/ 11 февраля 2011
class Main {
    public static void main(String args[]) throws Exception {
        ApplicationContext ac = new
          ClassPathXmlApplicationContext("context.xml", Main.class);
        DataSource dataSource = (DataSource) ac.getBean("dataSource");
// DataSource mysqlDataSource = (DataSource) ac.getBean("mysqlDataSource");

        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

        String prasobhName = 
        jdbcTemplate.query(
           "select first_name from customer where last_name like ?",
            new PreparedStatementSetter() {
              public void setValues(PreparedStatement preparedStatement) throws
                SQLException {
                  preparedStatement.setString(1, "nair%");
              }
            }, 
            new ResultSetExtractor<Long>() {
              public Long extractData(ResultSet resultSet) throws SQLException,
                DataAccessException {
                  if (resultSet.next()) {
                      return resultSet.getLong(1);
                  }
                  return null;
              }
            }
        );
        System.out.println(machaceksName);
    }
}
10 голосов
/ 07 июня 2010

Попробуйте следующее:

PreparedStatementCreator creator = new PreparedStatementCreator() {
    @Override
    public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
        PreparedStatement updateSales = con.prepareStatement(
        "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
        updateSales.setInt(1, 75); 
        updateSales.setString(2, "Colombian"); 
        return updateSales;
    }
};
3 голосов
/ 07 июня 2010

Я бы выделил обработку подготовленных операторов хотя бы для метода. В этом случае из-за отсутствия результатов это довольно просто (и при условии, что соединение является переменной экземпляра, которая не изменяется):

private PreparedStatement updateSales;
public void updateSales(int sales, String cof_name) throws SQLException {
    if (updateSales == null) {
        updateSales = con.prepareStatement(
            "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?");
    }
    updateSales.setInt(1, sales);
    updateSales.setString(2, cof_name);
    updateSales.executeUpdate();
}

В этот момент это просто вопрос вызова:

updateSales(75, "Colombian");

Что довольно просто интегрировать с другими вещами, да? И если вы будете вызывать метод много раз, обновление будет построено только один раз, и это значительно ускорит процесс. Ну, если предположить, что вы не делаете сумасшедших вещей, как, например, каждое обновление в отдельной транзакции ...

Обратите внимание, что типы являются фиксированными. Это связано с тем, что для любого конкретного запроса / обновления они должны быть исправлены, чтобы база данных могла эффективно выполнять свою работу. Если вы просто извлекаете произвольные строки из файла CSV, передайте их как строки. Там также нет блокировки; гораздо лучше вместо этого использовать отдельные соединения из одного потока.

2 голосов
/ 08 июня 2010

Я попробовал оператор SELECT теперь с PreparedStatement, но оказалось, что он был не быстрее шаблона Jdbc.Может быть, как и предполагал mezmo, он автоматически создает подготовленные операторы.

В любом случае, причина, по которой мои sql SELECT s были такими медленными, была другая.В предложении WHERE я всегда использовал оператор LIKE, когда все, что я хотел сделать, это найти точное совпадение.Как я выяснил, LIKE ищет шаблон и поэтому работает довольно медленно.

Сейчас я использую оператор =, и он намного быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...