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:
int rowCount =
this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class);
val rowCount = jdbcTemplate.queryForObject<Int>("select count(*) from t_actor")!!
La siguiente consulta utiliza una variable de enlace:
int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject(
"select count(*) from t_actor where first_name = ?", Integer.class, "Joe");
val countOfActorsNamedJoe = jdbcTemplate.queryForObject<Int>(
"select count(*) from t_actor where first_name = ?", arrayOf("Joe"))!!
La siguiente consulta busca String
:
String lastName = this.jdbcTemplate.queryForObject(
"select last_name from t_actor where id = ?",
String.class, 1212L);
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:
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);
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:
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;
});
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:
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);
}
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:
this.jdbcTemplate.update(
"insert into t_actor (first_name, last_name) values (?, ?)",
"Leonor", "Watling");
jdbcTemplate.update(
"insert into t_actor (first_name, last_name) values (?, ?)",
"Leonor", "Watling"
El siguiente ejemplo muestra la actualización de un registro existente:
this.jdbcTemplate.update( "actualizar t_actor set last_name =? donde id = ?", "Banjo", 5276L);
jdbcTemplate.update( "actualizar t_actor set last_name = ? donde id = ?, "Banjo", 5276L)
El siguiente ejemplo muestra cómo eliminar una entrada:
this.jdbcTemplate.update( "eliminar de t_actor donde id =?, Long.valueOf(actorId));
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:
this.jdbcTemplate.execute("crear tabla mytable (id entero, nombre varchar(100))");
jdbcTemplate.execute("crear tabla mytable (id entero, nombre varchar(100))")
El siguiente ejemplo llama a un procedimiento almacenado:
this.jdbcTemplate. update( "llamar a SUPPORT.REFRESH_ACTORS_SUMMARY(?)", Long.valueOf(unionId));
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:
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...
}
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:
@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...
}
- Anotar la clase con
@Repository
. - Anotar el definidor
DataSource
con@Autowired
. - Cree un nuevo
JdbcTemplate
usandoDataSource
.
@Repository
class JdbcCorporateEventDao(dataSource: DataSource) : CorporateEventDao {
private val jdbcTemplate = JdbcTemplate(dataSource)
// Implementaciones de métodos CorporateEventDao con soporte JDBC sigue...
}
- Anota la clase con
@Repository
. - Inyección del constructor de
DataSource
. - Crea un nuevo
JdbcTemplate
usandoDataSource
.
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
.