JdbcTemplate es la clase central en el paquete principal JDBC. Maneja la creación y liberación de recursos, lo que ayuda a evitar errores comunes como olvidar cerrar una conexión. Realiza las tareas básicas del flujo de trabajo principal de JDBC (como crear y ejecutar declaraciones), dejando que el código de la aplicación proporcione SQL y recupere los resultados. Clase JdbcTemplate:

  • Ejecuta consultas SQL

  • Actualiza declaraciones y llamadas a procedimientos almacenados

  • Itera a través de instancias de ResultSet y extrae los valores de los parámetros de retorno.

  • Captura excepciones JDBC y las convierte en un typed , una jerarquía de excepciones más descriptiva definida en el paquete org.springframework.dao. (Consulte Jerarquía coherente de excepciones).

Si usa la plantilla JdbcTemplate para su código, solo necesita implementar las interfaces de devolución de llamada proporcionándoles un contrato bien definido. Dada una Connection proporcionada por una clase JdbcTemplate, la interfaz de devolución de llamada PreparedStatementCreator crea una declaración compilada, proporcionando el SQL y todos los parámetros necesarios. Lo mismo ocurre con la interfaz CallableStatementCreator, que crea declaraciones invocables. La interfaz RowCallbackHandler recupera los valores de cada fila del ResultSet.

Puedes usar JdbcTemplate dentro de un Implementación de DAO al crear una instancia directa con una referencia a DataSource, o puede configurarlo en el contenedor Spring IoC y pasarlo al DAO como una referencia de bean.

DataSource siempre debe configurarse como un bean en el contenedor Spring IoC. En el primer caso, el frijol pasa directamente al servicio; en el segundo caso, se pasa a la plantilla preparada.

Todo el SQL producido por esta clase se registra en el nivel DEBUG en la categoría correspondiente al nombre de clase completo de la instancia de plantilla (normalmente JdbcTemplate, pero puede ser diferente si está utilizando una subclase personalizada de JdbcTemplate)

Las siguientes secciones proporcionan algunos ejemplos de usando JdbcTemplate. Estos ejemplos no son una lista exhaustiva de todas las funciones proporcionadas por JdbcTemplate. Ver el complemento javadoc .

Construcción de consultas (SELECT)

La siguiente consulta le permite obtener el número de filas en una relación:

Java
int rowCount =
        this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class);
Kotlin
val rowCount = jdbcTemplate.queryForObject<Int>("select count(*) from t_actor")!!

La siguiente consulta utiliza una variable de enlace:

Java

int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject(
        "select count(*) from t_actor where first_name = ?", Integer.class, "Joe");            
        
Kotlin

val countOfActorsNamedJoe = jdbcTemplate.queryForObject<Int>(
        "select count(*) from t_actor where first_name = ?", arrayOf("Joe"))!!

La siguiente consulta busca String:

Java

String lastName = this.jdbcTemplate.queryForObject(
        "select last_name from t_actor where id = ?",
        String.class, 1212L);
Kotlin

val lastName = this.jdbcTemplate.queryForObject<String>(
        "select last_name from t_actor where id = ?",
        arrayOf(1212L))!!

La siguiente consulta busca y completa un dominio objeto:

Java

Actor actor = jdbcTemplate.queryForObject(
        "select first_name, last_name from t_actor where id = ?",
        (resultSet, rowNum) -> {
            Actor newActor = new Actor();
            newActor.setFirstName(resultSet.getString("first_name"));
            newActor.setLastName(resultSet.getString("last_name"));
            return newActor;
        },
        1212L);
Kotlin

val actor = jdbcTemplate.queryForObject(
            "select first_name, last_name from t_actor where id = ?",
            arrayOf(1212L)) { rs, _ ->
        Actor(rs.getString("first_name"), rs.getString("last_name"))
    }

La siguiente consulta busca y completa una lista de dominios objetos:

Java

List<Actor> actors = this.jdbcTemplate.query(
        "select first_name, last_name from t_actor",
        (resultSet, rowNum) -> {
            Actor actor = new Actor();
            actor.setFirstName(resultSet.getString("first_name"));
            actor.setLastName(resultSet.getString("last_name"));
            return actor;
        });
Kotlin

val actors = jdbcTemplate.query("select first_name, last_name from t_actor") { rs, _ ->
        Actor(rs.getString("first_name"), rs.getString("last_name"))

Si los dos últimos fragmentos de código realmente existieron en el mismo application , entonces tendría sentido eliminar la duplicación presente en las dos expresiones lambda RowMapper y extraerlas en un solo campo, al que luego se podría hacer referencia mediante métodos DAO según sea necesario. Por ejemplo, es mejor escribir el fragmento de código anterior de la siguiente manera:

Java

private final RowMapper<Actor> actorRowMapper = (resultSet, rowNum) -> {
    Actor actor = new Actor();
    actor.setFirstName(resultSet.getString("first_name"));
    actor.setLastName(resultSet.getString("last_name"));
    return actor;
};
public List<Actor> findAllActors() {
    return this.jdbcTemplate.query("select first_name, last_name from t_actor", actorRowMapper);
}
Kotlin

val actorMapper = RowMapper<Actor> { rs: ResultSet, rowNum: Int ->
    Actor(rs.getString("first_name"), rs.getString("last_name"))
}
fun findAllActors(): List<Actor> {
    return jdbcTemplate.query("select first_name, last_name from t_actor", actorMapper)
}

Actualizar (INSERT, ACTUALIZAR y DELETE) usando JdbcTemplate

Puedes usar el método update(..) para realizar operaciones de inserción, actualización y eliminación. Los valores de los parámetros generalmente se proporcionan como argumentos variables o, alternativamente, como una matriz de objetos.

El siguiente ejemplo muestra cómo insertar una nueva entrada:

Java

this.jdbcTemplate.update(
        "insert into t_actor (first_name, last_name) values (?, ?)",
        "Leonor", "Watling");
Kotlin

jdbcTemplate.update(
        "insert into t_actor (first_name, last_name) values (?, ?)",
        "Leonor", "Watling"

El siguiente ejemplo muestra la actualización de un registro existente:

Java
this.jdbcTemplate.update( "actualizar t_actor set last_name =? donde id = ?", "Banjo", 5276L);
Kotlin
jdbcTemplate.update( "actualizar t_actor set last_name = ? donde id = ?, "Banjo", 5276L)

El siguiente ejemplo muestra cómo eliminar una entrada:

Java
this.jdbcTemplate.update( "eliminar de t_actor donde id =?, Long.valueOf(actorId));
Kotlin
jdbcTemplate.update("eliminar de t_actor donde id =?, actorId.toLong())

Otras operaciones JdbcTemplate

Puede utilizar el método execute(..) para ejecutar SQL arbitrario. En consecuencia, este método se utiliza a menudo para declaraciones en lenguaje de definición de datos (DDL). Está muy cargado de opciones que aceptan interfaces de devolución de llamada, vinculan matrices de variables, etc. El siguiente ejemplo crea una tabla:

Java
this.jdbcTemplate.execute("crear tabla mytable (id entero, nombre varchar(100))");
Kotlin
jdbcTemplate.execute("crear tabla mytable (id entero, nombre varchar(100))") 

El siguiente ejemplo llama a un procedimiento almacenado:

Java
this.jdbcTemplate. update( "llamar a SUPPORT.REFRESH_ACTORS_SUMMARY(?)", Long.valueOf(unionId));
Kotlin
jdbcTemplate .update( "call SUPPORT.REFRESH_ACTORS_SUMMARY(?)", unionId.toLong())

Soporte mejorado para procedimientos almacenados se describe con más detalle.

Prácticas recomendadas para trabajar con JdbcTemplate

Una vez completada la configuración, las instancias de la clase JdbcTemplate son seguras para subprocesos. Esto es importante porque significa que puede configurar una instancia JdbcTemplate y luego inyectar de forma segura esa referencia compartida en múltiples DAO (o repositorios). JdbcTemplate tiene estado porque almacena una referencia a DataSource, pero este estado no es un estado de diálogo.

Prácticas recomendadas al utilizar JdbcTemplate (y la clase asociada NamedParameterJdbcTemplate ) es la configuración de DataSource en el archivo de configuración de Spring, y luego inyectar la dependencia de ese bean DataSource común en las clases DAO. JdbcTemplate se crea en el configurador de DataSource. Esto da como resultado un DAO que se parece a esto:

Java

public class JdbcCorporateEventDao implements CorporateEventDao {
    private JdbcTemplate jdbcTemplate;
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
    // Las implementaciones de los métodos CorporateEventDao con soporte JDBC siguen...
}
Kotlin

class JdbcCorporateEventDao(dataSource: DataSource) : CorporateEventDao {
    private val jdbcTemplate = JdbcTemplate(dataSource)
    // Las implementaciones habilitadas para JDBC de los métodos CorporateEventDao siguen...
}

El siguiente ejemplo muestra la configuración XML correspondiente:


<?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xmlns:context="http://www.springframework.org/schema/context"
                   xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    <bean id="corporateEventDao" class="com.example.JdbcCorporateEventDao">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <context:property-placeholder location="jdbc.properties"/>
</beans>

Una alternativa a la configuración explícita es utilizar el escaneo de beans y admitir anotaciones para la inyección de dependencias. En este caso, puede marcar la clase con la anotación @Repository (lo que la convierte en candidata para el escaneo de componentes) y marcar el definidor DataSource con @Autowired anotación. El siguiente ejemplo muestra cómo hacer esto:

Java

@Repository 
public class JdbcCorporateEventDao implements CorporateEventDao {
    private JdbcTemplate jdbcTemplate;
    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource); 
    }
    // Las implementaciones habilitadas para JDBC de los métodos CorporateEventDao siguen...
}
  1. Anotar la clase con @Repository.
  2. Anotar el definidor DataSource con @Autowired.
  3. Cree un nuevo JdbcTemplate usando DataSource.
Kotlin

@Repository 
class JdbcCorporateEventDao(dataSource: DataSource) : CorporateEventDao { 
    private val jdbcTemplate = JdbcTemplate(dataSource) 
    // Implementaciones de métodos CorporateEventDao con soporte JDBC sigue...
}
  1. Anota la clase con @Repository.
  2. Inyección del constructor de DataSource.
  3. Crea un nuevo JdbcTemplate usando DataSource .

El siguiente ejemplo muestra la configuración XML correspondiente:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- Search the base application package for classes with the @Component annotation to configure as beans -->
    <context:component-scan base-package="org.springframework.docs.test" />
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <context:property-placeholder location="jdbc.properties"/>
</beans>

Si está utilizando la clase JdbcDaoSupport de Spring y tiene varias clases DAO habilitadas para JDBC adjuntas entonces su subclase hereda el método setDataSource(..) de la clase JdbcDaoSupport. Puede determinar si heredar de esta clase. La clase JdbcDaoSupport se proporciona únicamente por conveniencia.

Independientemente de cuál de los estilos de inicialización de plantilla descritos anteriormente decida usar (o no usar), rara vez es necesario cree una nueva instancia de JdbcTemplate siempre que necesite ejecutar SQL. Una vez completada la configuración, la instancia JdbcTemplate es segura para subprocesos. Si su aplicación accede a varias bases de datos, es posible que necesite varias instancias JdbcTemplate, lo que requiere varias fuentes de datos y, en consecuencia, varias instancias configuradas de forma diferente de JdbcTemplate.