No se necesita mucho código para ejecutar una declaración SQL. Requiere DataSource y JdbcTemplate, incluidos los métodos auxiliares que se proporcionan con JdbcTemplate. El siguiente ejemplo muestra lo que se debe incluir en una clase mínima pero completamente funcional que crea una nueva tabla:

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

Ejecución de consultas

Algunos métodos de consulta devuelven un valor único. Para obtener un contador o un valor específico de una sola línea, use queryForObject(..). Este último convierte el Type devuelto de JDBC a la clase Java pasada como argumento. Si la conversión de tipo no es válida, se generará una excepción InvalidDataAccessApiUsageException. El siguiente ejemplo contiene dos métodos de consulta, uno para int y el otro para 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")
}

Además de los métodos de consulta de resultado único, varios métodos devuelven una lista con una entrada para cada fila que devuelve la consulta. El método más escrito es queryForList(..), que devuelve una List, donde cada elemento es un Map que contiene una entrada para cada columna. usando el nombre de la columna como clave. Si agrega un método al ejemplo anterior para obtener una lista de todas las cadenas, podría verse así:

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

La lista resultante se verá así:

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

Actualización de base de datos

El siguiente ejemplo actualiza una columna para una clave principal específica:

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

En el ejemplo anterior, la instrucción SQL contiene marcadores de posición para parámetros de cadena. Puede pasar valores de parámetros como argumentos de longitud variable (varargs) o, alternativamente, como una matriz de objetos. Por lo tanto, debe envolver explícitamente los tipos primitivos en clases contenedoras de tipos primitivos o utilizar el autoboxing.

Obtener claves generadas automáticamente

El método auxiliar update() admite la recuperación de las claves principales generadas por la base de datos. Este soporte es parte del estándar JDBC 3.0. Para obtener más información, consulte el Capítulo 13.6 de la especificación. El método toma PreparedStatementCreator como primer argumento y así es como se especifica la declaración de inserción requerida. El otro argumento es KeyHolder, que contiene la clave generada cuando la actualización se realiza correctamente. No existe una forma estándar única de crear una PreparedStatement correspondiente (lo que explica por qué la firma del método es como es). El siguiente ejemplo funciona en Oracle, pero es posible que no funcione en otras plataformas:

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() ahora contiene la clave generada
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() ahora contiene la clave generada