It doesn't take much code to execute an SQL statement. Requires DataSource and JdbcTemplate, including the helper methods that are provided with JdbcTemplate. The following example shows what should be included in a minimal but fully functional class that creates a new table:

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))")
    }
}

Running queries

Some query methods return a single value. To get a counter or a specific value from a single line, use queryForObject(..). The latter converts the returned Type from JDBC to the Java class passed as an argument. If the type conversion is invalid, an InvalidDataAccessApiUsageException exception will be thrown. The following example contains two query methods, one for int and the other for 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")
}

In addition to the single-result query methods, several methods return a list with an entry for each row that the query returned. The most typed method is queryForList(..), which returns a List, where each element is a Map containing one entry for each column, using column name as key. If you add a method to the previous example to get a list of all strings, it might look like this:

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")
}

The resulting list will look like this:

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

Database update

The following example updates a column for a specific primary key:

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)
    }
}

In the previous example, the SQL statement contains placeholders for string parameters. You can pass parameter values as variable length arguments (varargs) or, alternatively, as an array of objects. Thus, you need to explicitly wrap primitive types in primitive type wrapper classes, or use autoboxing.

Getting automatically generated keys

The update() helper method supports retrieving the primary keys generated by the database. This support is part of the JDBC 3.0 standard. For details, see Chapter 13.6 of the specification. The method takes PreparedStatementCreator as the first argument, and this is how the required insertion statement is specified. The other argument is KeyHolder, which contains the generated key when the update returns successfully. There is no single standard way to create a corresponding PreparedStatement (which explains why the method signature is the way it is). The following example works on Oracle, but may not work on other platforms:

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() now contains the generated key
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() now contains the generated key