Для выполнения SQL-инструкции не требуется много кода. Требуется DataSource и JdbcTemplate, включая вспомогательные методы, которые предоставляются вместе с JdbcTemplate. В следующем примере показано, что должно быть в составе минимального, но полностью функционального класса, который создает новую таблицу:

Java
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class ExecuteAStatement {
    private JdbcTemplate jdbcTemplate;
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
    public void doExecute() {
        this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
    }
}
Kotlin
import javax.sql.DataSource
import org.springframework.jdbc.core.JdbcTemplate
class ExecuteAStatement(dataSource: DataSource) {
    private val jdbcTemplate = JdbcTemplate(dataSource)
    fun doExecute() {
        jdbcTemplate.execute("create table mytable (id integer, name varchar(100))")
    }
}

Выполнение запросов

Некоторые методы запросов возвращают единственное значение. Чтобы получить счётчик или конкретное значение из одной строки, используйте queryForObject(..). Последний преобразует возвращаемый Type из JDBC в Java-класс, переданный в качестве аргумента. Если преобразование типа недействительно, будет сгенерировано исключение InvalidDataAccessApiUsageException. Следующий пример содержит два метода запроса, один для int, а другой для String:

Java
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class RunAQuery {
    private JdbcTemplate jdbcTemplate;
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
    public int getCount() {
        return this.jdbcTemplate.queryForObject("select count(*) from mytable", Integer.class);
    }
    public String getName() {
        return this.jdbcTemplate.queryForObject("select name from mytable", String.class);
    }
}
Kotlin
import javax.sql.DataSource
import org.springframework.jdbc.core.JdbcTemplate
class RunAQuery(dataSource: DataSource) {
    private val jdbcTemplate = JdbcTemplate(dataSource)
    val count: Int
        get() = jdbcTemplate.queryForObject("select count(*) from mytable")!!
    val name: String?
        get() = jdbcTemplate.queryForObject("select name from mytable")
}

В дополнение к методам запроса с единственным результатом, несколько методов возвращают список с записью для каждой строки, которую вернул запрос. Наиболее типизированным методом является queryForList(..), который возвращает List, где каждый элемент является Map, содержащим по одной записи для каждого столбца, используя имя столбца в качестве ключа. Если к предыдущему примеру добавить метод для получения списка всех строк, то он может выглядеть следующим образом:

Java
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
    this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public List<Map<String, Object>> getList() {
    return this.jdbcTemplate.queryForList("select * from mytable");
}
Kotlin
private val jdbcTemplate = JdbcTemplate(dataSource)
fun getList(): List<Map<String, Any>> {
    return jdbcTemplate.queryForList("select * from mytable")
}

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

[{name=Bob, id=1}, {name=Mary, id=2}]

Обновление базы данных

В следующем примере столбец обновляется для определенного первичного ключа:

Java
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class ExecuteAnUpdate {
    private JdbcTemplate jdbcTemplate;
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
    public void setName(int id, String name) {
        this.jdbcTemplate.update("update mytable set name = ? where id = ?", name, id);
    }
}
Kotlin
import javax.sql.DataSource
import org.springframework.jdbc.core.JdbcTemplate
class ExecuteAnUpdate(dataSource: DataSource) {
    private val jdbcTemplate = JdbcTemplate(dataSource)
    fun setName(id: Int, name: String) {
        jdbcTemplate.update("update mytable set name = ? where id = ?", name, id)
    }
}

В предыдущем примере SQL-инструкция содержит плейсхолдеры для параметров строки. Можно передать значения параметров как аргументы переменной длинны (varargs) или, в качестве альтернативы, как массив объектов. Таким образом, вам нужно явным образом обернуть примитивные типы в классы-обертки примитивных типов, либо использовать автоупаковку.

Получение автоматически сгенерированных ключей

Вспомогательный метод update() поддерживает получение первичных ключей, созданных базой данных. Эта поддержка является частью стандарта JDBC 3.0. Подробности см. в главе 13.6 спецификации. Метод принимает PreparedStatementCreator в качестве первого аргумента, и именно так задается требуемая инструкция вставки. Другим аргументом является KeyHolder, который содержит сгенерированный ключ при успешном возврате из обновления. Не существует единого стандартного способа создания соответствующего PreparedStatement (что объясняет, почему сигнатура метода такая, какая она есть). Следующий пример работает на Oracle, но может не работать на других платформах:

Java
final String INSERT_SQL = "insert into my_test (name) values(?)";
final String name = "Rob";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
    PreparedStatement ps = connection.prepareStatement(INSERT_SQL, new String[] { "id" });
    ps.setString(1, name);
    return ps;
}, keyHolder);
// keyHolder.getKey() теперь содержит сгенерированный ключ
Kotlin
val INSERT_SQL = "insert into my_test (name) values(?)"
val name = "Rob"
val keyHolder = GeneratedKeyHolder()
jdbcTemplate.update({
    it.prepareStatement (INSERT_SQL, arrayOf("id")).apply { setString(1, name) }
}, keyHolder)
// keyHolder.getKey() теперь содержит сгенерированный ключ