Recorriendo Spring
- Spring: Introducción + Inyección de dependencias
- Spring: AOP Programación Orientada a Aspectos
- Spring: AOP con Aspect mediante archivos xml y Anotation.
- Spring: Mejorando JDBC
- Spring Transaction
- Spring: Mejorando el Trabajo con Hibernate ORM
- Spring MVC una recorrida contando lo bueno y lo malo (En contruccion)
- Spring Security, pensando en seguridad (En contruccion)
- Spring: Remoting gestionando conexiones
- Spring: Spring-WS con JAXB + Hibernate + DAO
- Spring: JMS
- Spring: Automatizando pruebas con JUNIT STUBS Mock (En contruccion)
El objetivo es proporcionar un pantallaso de como se hacia JDBC con la api nativa y como puede hacer JDBC con el soporte SPRING.
Si programaste en java de seguro le diste una pasada a JDBC por que no creo que hayas amado hibernate todo tu vida perdiendo percepción de otras formas de tratamiento de datos.
Pero la primera pregunta seria que es JDBC ?
JAVA DATABASE CONNECTIVITY es una API de java para conectar aplicaciones a base de datos, cuenta con una arquitectura modular, una misma interfaz para diferentes motores de base de datos implementando un gestor de drive para cada motor.
Que quiere decir que cada motor proporciona un drive que posibilita que JDBC realice la magia de la conectividad.
Pero para toda esta estructura de comunicación utiliza un paquete llamado java.sql
Los controladores de las BD son:
- Clase DriverManager: Permite establecer y gestionar conexiones a las BD
- Clase SQLPermission: Proporciona los permisos para poder usar el DriverManager a código en ejecución dentro de un Security Manager (por ejemplo applets)
- Interfaz Driver: Métodos para registrar y conectar controladores basados en tecnología JDBC
- Clase DriverPropertyInfo: Propiedades de un controlador
- Excepciones: dispone de SQLException y SQLWarning
Interfaz con la aplicación: es claro que nuestra aplicación tendrá como responsabilidad el uso de sentencias que posibilitan el acceso al modelo de datos.
• Connection: Métodos para crear instrucciones y para gestionar conexiones y sus propiedades
• Statement: Permite enviar instrucciones a la BD
• PreparedStatement: Permite usar instrucciones preparadas o SQL básicas
• CallableStatement: Llamada a procedimientos almacenados en la BD
• Savepoint: Puntos de recuperación en una transacción
Recuperación de los resultados de la consulta a la BD
• ResultSet: Conjunto de resultados que se devuelven de una query
• ResultSetMetaData: Información sobre las columnas del objeto ResultSe
En cuanto a lo que se refiere al como trabajar por lo general se sigue un flujo de trabajo como el siguiente.
- Establecer la conexión con la BD
- Cargar controladores (si se usa una versión de Java inferior a la 6)
- Establecer la conexión
- Crear un objeto Statement para hacer petición a la BD
- Asociar una sentencia SQL al objeto Statement
- Proporcionar valores de los parámetros
- Ejecutar el objeto Statement
- Procesar los resultados
- Liberar recursos (cerrar la conexión)
Nota: Si es necesario, se pueden ejecutar varias instrucciones dentro de una transacción (propiedades ACID)
- Abrir transacción
- Crear y ejecutar instrucciones
- Procesar resultados
- Cerrar transacción
Pero la realidad es que esto siempre fue mas facil de observar si lo miramos a nivel código por ejemplo visualicemos una clase CustomerDaoImpl que tendria la responsabilidad de realizar las operaciones de la base de datos.
Por supuesto la clase recibirá el datasource de una capa superior
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
El metodo insertar recibirá un objeto de tipo customer para que el método pueda procesarlo para la operación con la base de datos, en su interior lo que por lo general realizaríamos en primera instancia un amplo manejo de excepciones para la operación con JDBC y por otro lado realizaríamos un procesamiento normal, obtener la conexión con la base de datos, preparar el el comando que dispararemos , setear los parametros del query que vamos a enviar, ejecutaremos el comando y gestionaremos el cierre de la conexión intentando que no quede colgada ninguna conexión.
public void insert(Customer customer){
String sql = "INSERT INTO CUSTOMER " +
"(CUST_ID, NAME, AGE) VALUES (?, ?, ?)";
Connection conn = null;
try {
conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, customer.getCustId());
ps.setString(2, customer.getName());
ps.setInt(3, customer.getAge());
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {}
}
}
}
Nota: en los viejos tiempos muchas veces el low performance de una aplicacion desarrollada en JDBC, estaba en que no estaba gestionada las aperturas y cierres de conexiones en la interacción con la base de datos, donde teníamos un programador feliz de haber terminado un desarrollo y de pronto 1 semana después te decía el analista, el cliente dice que funciona muy lenta la aplicación entonces comenzabas a monitorear el servidor y tenias conexiones colgadas por todos lados, conexiones que nunca se cerraban.
Como nota final había un manejo de excepciones muy grande que se realizaba sobre toda una capa de negocio desarrollada con jdbc a fin de prevenir problemas de interacción y las conexiones, tareas repetitivas y tediosas.
Ahora para los que ya trabajaron bajo el modelo tradicional de trabajo con JDBC conoce un poco sobre las limitaciones que ofrecía el esquema de trabajo:
- Se debe escribir demasiado código para cosas simples como operaciones CRUD.
- Mucho del código a escribir es repetitivo lo que puede llevar a errores o inconsistencias.
- Se debe manejar la creación de las conexiones, la preparación de las consultas su ejecución y el cierre de las conexiones.
- Se debe manejar las excepciones dado que no todas pueden ser capturadas en JDBC, por lo que requiere mucho control un trabajo bien realizado.
Como todo el mundo una alternativa es migrar por supuesto a un esquema basado en ORM que nos facilite el trabajo y elimine tareas repetitivas, pero de seguro hay gente que puede pensar que para una implementacion de este tipo, el desarrollo debe justificarlo por lo que es logico que un programador en la actualidad se encuentra mantenimientos que trabajan con JDBC puro, por lo que es una alternativa de mejorar las prestaciones del codigo sin emprender una migración de hitos tecnológicos que pueda tener muchas horas de desarrollo, por que spring es fácil adaptable a proyectos.
El valor agregado proporcionado por la abstracción de Spring Framework JDBC es quizás la mejor manera de mostrar la secuencia de las acciones indicadas en la tabla de abajo. La tabla muestra las acciones que Spring se hará cargo y las acciones que son responsabilidad suya, el desarrollador de la aplicación.
Acción
|
Spring
|
Nosotros
|
Definir los parámetros de conexión.
|
X
|
|
Abrir la conexión.
|
X
|
|
Especificar la sentencia SQL.
|
X
|
|
Declarar parámetros y proporcionar
valores de los parámetros.
|
X
|
|
Elaborar y ejecutar la sentencia.
|
X
|
|
Configurar el bucle para iterar a través
de los resultados (si los hay).
|
X
|
|
Hacer el trabajo para cada iteración.
|
X
|
|
Procesar cualquier excepción.
|
X
|
|
Manejar las transacciones.
|
X
|
|
Cerrar
connection, statement y resultset.
|
X
|
Usted puede elegir entre varios enfoques para acceder a la base de datos JDBC.
Además de los tres JdbcTemplate, un nuevo enfoque SimpleJdbcInsert y SimplejdbcCall optimizan los metadatos de la base de datos.
- JdbcTemplate es el clásico enfoque de Spring JDBC y el más popular. Este enfoque de "nivel más bajo" es el que todos los otros utilizan a nivel interno.
- NamedParameterJdbcTemplate envuelve un JdbcTemplate para proporcionar los nombres de los parámetros en lugar del tradicional marcador de posición "?" de JDBC.
- SimpleJdbcTemplate combina las operaciones de uso más frecuente de dbcTemplate y NamedParameterJdbcTemplate.
- SimpleJdbcInsert y SimpleJdbcCall optimizan el metadato de la base de datos para limitar la cantidad de configuración necesaria. Este enfoque simplifica la codificación de manera que usted sólo necesita proporcionar el nombre de la tabla o un procedimiento y proporcionar un mapa de parámetros que coincidan con los nombres de las columnas. Esto sólo funciona si la base de datos proporciona los metadatos adecuados. Si la base de datos no proporciona estos metadatos, usted tendrá que proporcionar la configuración explícita de los parámetros.
La abstracción del framework de Spring Framework JDBC consiste en cuatro paquetes diferentes, core, datasource, object, y support.
- El paquete org.springframework.jdbc.core contiene la clase JdbcTemplate y sus diferentes interfaces de retro llamada, además de una variedad de clases relacionadas. Un subpaquete llamado org.springframework.jdbc.core.simple contiene la clase SimpleJdbcTemplate y las clases relacionadas SimpleJdbcInsert y SimpleJdbcCall. Otro subpaquete llamado org.springframework.jdbc.core.namedparam contiene la clase NamedParameterJdbcTemplate y las clases relacionadas de apoyo.
- El paquete org.springframework.jdbc.datasource contiene una clase de utilidad para el fácil acceso a DataSource, y varias implementaciones simples de DataSource que pueden ser utilizadas para probar y ejecutar sin modificar el código JDBC fuera de un contenedor Java EE. Un subpaquete llamado org.springfamework.jdbc.datasource.embedded proporciona soporte para crear instancias de base de datos en memoria utilizando los motores de bases de datos Java, tales como HSQL y H2.
- El paquete org.springframework.jdbc.support proporciona una funcionalidad de traducción SQLException y algunas clases de utilidad. Las excepciones que se producen durante el procesamiento JDBC son traducidas a excepciones definidas en el paquete org.springframework.dao. Esto significa que utilizando el código, la capa de abstracción de Spring JDBC no necesita implementar un tratamiento de errores de JDBC o un RDBMS específico.
La clase JdbcTemplate ejecuta consultas SQL, sentencias de actualización y llamadas a procedimientos almacenados, realiza iteraciones sobre ResultSets y la extracción de valores de los parámetros devueltos. También captura las excepciones JDBC y las traduce a genéricas más informativas, que se define en el paquete org.springframework.dao.
En primera instancia como buena practica utilizaremos el patron DAO para nuestros ejemplos.
"Data Access Object" un patrón de diseño muy común que se usa para diseñar como los objetos de negocio de una aplicación deben usar los objetos encargados del acceso a los datos.
Como pueden ver los objetos del negocio acceden a los DAO a través de sus interfaces, de esta manera no dependen de una implementación en específico lo que hace que esta implementación se pueda cambiar fácilmente. También facilita las pruebas que se pueden realizar sobre esta implementación, ya que se pueden crear implementaciones falsas menos complejas que las implementaciones reales con fines de prueba.
Para nuestro ejemplo vamos a trabajar como siempre con un proyecto creado con Maven para que nos solucione las dependencias.
Por otro lado abordaremos la utilización de JdbcTemplate en nuestro proyecto dado que es la implementacion nativa que utilizan las diferentes formas que proporciona spring para trabajar con JDBC.
En esta oportunidad utilizaremos MYSQL como motor de base de datos en donde vamos a crear una base de datos llamada estudiantes y posterior crearemos una tabla estudiantes con la siguiente estructura.
CREATE TABLE Estudiante(
ID INT NOT NULL AUTO_INCREMENT,
NOMBRE VARCHAR(20) NOT NULL,
EDAD INT NOT NULL,
PRIMARY KEY (ID)
);
como siempre el objetivo es con fines educativos por lo que no desarrollaremos grandes códigos pero si aplicaremos buenas practicas que vayan formando nuestra forma de trabajar.
La estructura de nuestro proyecto es la siguiente
Pero es la hora de recorrer nuestro proyecto a fin de poder hablar de las virtudes de utilizacion de spring para mejorar JDBC.
Pom.xml: Nuestro archivo de configuración de dependencias para el proyecto.
Nota: no va presentar grandes inclusiones por un lado las típicas referencias de trabajo de spring y por supuesto el conector asociado a MYSQL.
com.company.modelo.Estudiante.java: Nuestro pojo que por la simplicidad del ejemplo solo tendra los campos asociados a la tabla con la que trabajaremos.
Nota: Podemos observar que solo tiene 3 campos ID, NOMBRE, EDAD que son casualmente los campos de nuestra tabla estudiantes en MYSQL.
com.company.dao.EstudianteDao.java: Definimos el contrato de los métodos que deberán incluir las clases que implementen esta interfaz.
Nota: Como particularidad debemos recalcar el método setdatasource que es por donde podremos suministrar el datasource de conexión con la base de datos y luego la definición de los métodos asociados a un CRUD.
com.company.dao.EstudianteJDBCTemplate.java: Es la implementacion dao, que logicamente implementa el codigo para las operaciones CRUD sobre la tabla estudiante.
El código de la implementacion es la que nos permite indagar sobre las ventajas de spring sobre el manejo de JDBC.
Primero lo que debemos recalcar es la utilizacion de 2 variables privadas
La primera hace referencia al datasource de la base de datos que sera sostenida en la tabla
private DataSource dataSource;
La segunda hace referencia a la template para trabajar con JDBC que nos proporciona spring.
private JdbcTemplate jdbcTemplateObject;
El primer metodo que vamos a encontrar es el setDataSource que como parametro de ingreso recibe un datasource que lógicamente sera suministrado por inyección dado que este objeto esta precargado en el spring bean configuration que veremos mas adelante. En su interior el metodo asigna el valor a la variable privada para este fin, pero por otro lado genera una instancia de la template que nos proporciona spring pasandole la conexion con la base de datos para se encargue de ahora en mas.
Los métodos que realizan operaciones de actualización en la clase Agregar, Eliminar y Actualizar tienen una misma lógica de funcionamiento.
Primero definimos la cadena con la sentencia SQL indicando con ? la necesidad de un parámetro externo, ejemplo
insert into estudiante (nombre, edad) values (?, ?)
delete from estudiante where id = ?
update estudiante set edad = ? where id = ?
lo loco es que spring con solo hacer referencia al metodo update de la template , pasandole la query y los parametros que tiene que remplazar en la misma se encarga de todo.
sisi!!
yo pongo jdbcTemplateObject.update(query.., parametro1, parametro 2 .....parametro n); con esto spring se encarga de todo, es decir que si le paso una sentencia de insert va realizar un alta, si le paso una update realizara una actualizacion y si le paso una sentencia delete realizara una eliminacion.
ahora lo que llega es analizar los metodos de buscar un registro en particular el metodo getEstudiante y listarEstudiantes() donde la unica diferencia es que el primero retorna solo un objeto y el segundo retorna una lista de objetos, pero en su codigo no presentan casi ninguna diferencia dado que ambas realizan un procesamiento similar.
Para la busqueda de un registro utiliza el metodo queryForObject a quien le pasa la sentencia de consulta SQL, le pasa la generación de la instancia para el objeto de retorno y genera una instancia de la clase Mapper quien recibirá el resultado de la consulta y generara un objeto para cada fila del resulset que reciba que para este caso sera solo 1.
String SQL = "select * from estudiante where id = ?";
Estudiante student = jdbcTemplateObject.queryForObject(SQL,
new Object[]{id}, new EstudianteMapper());
Para la búsqueda de varios registros utiliza el método query a quien le pasa la sentencia SQL y una nueva instancia del objeto mapper que en este caso retorna una lista de objetos generada como producto de la generación de un objeto por cada fila del resulset resultante.
String SQL = "select * from estudiante";
List students = jdbcTemplateObject.query(SQL,
new EstudianteMapper());
A mi modo de ver las cosas spring no hace otra cosa que lo que nosotros hacíamos antes de manera manual, por un lado generábamos una clase base que contenga método para operaciones de actualización y consulta y luego utilizábamos en las implementaciones la llamada a estos métodos para evitar código repetitivo y estos métodos ya tenían una gestión de excepciones propia ...etc la diferencia que ahora estas clases manuales te las brinda spring con la diferencia que están mucho mas cuidadas que quizás las que programábamos nosotros o quizás no, dado que la nuestra era propia acuerdo a nuestras necesidades. En el pasado hubiera significado que los programadores no tuviéramos que haber programado clases DAL propias para esta gestión.
com.company.dao.EstudianteMapper.java: Realiza el mapeo de cada fila de un resulset en un objeto del tipo estudiante identificado.
Nota: Recordemos que cuando usábamos un JDBC normal, después de hacer un
src/main/resource/springjdbc.xml: Nuestro archivo de configuración de bean del proyecto.
Nota: El archivo no presenta grandes novedades en primera instancia la declaración de nuestro dataource y la inyeccion del mismo en la clase EstudianteJDBCTemplate.
com.company.test.EstudianteTest.java: Nuestra clase de test del proyecto que es donde podremos ver el funcionamiento de las clases antes mencionadas.
Nota: Donde no hacemos nada raro de la habitual, pero genero el contexto apartir del spring bean configuración, segundo obtengo el bean EstudianteJDBCTemplate con el que ejecutaremos algunos de los metodos implementados en la clase para verificar su funcionamiento.
Analizando el resultado de ejecución:
El código del proyecto se lo puede descargar desde aquí. codigofuente.zip
Nota Final: Reduce gran cantidad de código repetido que tenia JDBC, me quita la responsabilidad de gestionar las excepciones por que lo realiza spring, me quita la responsabilidad de controlar las conexiones con la base de datos, me colabora con la generación de listas de objetos permitiendo un mapeo parcial con el contenido de la base de datos.
Listo me solucionaste todos los problemas por lo que migre a utilizar formas de acceso a la base de datos mas potentes HIBERNATE,.... YA FUE ME DECIDÍ LARGO TODO ESTO Y COMIENZO A DESARROLLAR CON ESTO!!! .mmm no hay chance JAJA si es verdad mejoro mucho el trabajo con JDBC pero no tiene comparacion en la facilidad que nos brindan estas grandes herramientas de trabajo, pero si es bueno tenerlo en cuenta cuando nos topamos con algún proyecto viejo que podríamos optimizar para no migrarlo o algun desarrollo pequeño para lo que HIBERNATE le quede grande.
Conociendo un poco de JdbcDaoSupport
Un plus seria Extends JdbcDaoSupport a nuestra clase de implementacion dao, dando basicamente le quitamos la responsabilidad a JdbcTemplate de gestionar la obtencion del datasource, dado que con solo inyectar el datasource a la clase de implementacion dao, jdbcDaoSupport se encargaria de manera automatica de la gestion del medio de dato.
Es decir este método en la clase de implementacion ya no seria necesario
public void setDataSource(DataSource dataSource) {
ID INT NOT NULL AUTO_INCREMENT,
NOMBRE VARCHAR(20) NOT NULL,
EDAD INT NOT NULL,
PRIMARY KEY (ID)
);
como siempre el objetivo es con fines educativos por lo que no desarrollaremos grandes códigos pero si aplicaremos buenas practicas que vayan formando nuestra forma de trabajar.
La estructura de nuestro proyecto es la siguiente
Pero es la hora de recorrer nuestro proyecto a fin de poder hablar de las virtudes de utilizacion de spring para mejorar JDBC.
Pom.xml: Nuestro archivo de configuración de dependencias para el proyecto.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.company</groupId> <artifactId>jdbcspring01</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <spring.version>3.0.5.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.26</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> </dependencies> </project>
Nota: no va presentar grandes inclusiones por un lado las típicas referencias de trabajo de spring y por supuesto el conector asociado a MYSQL.
com.company.modelo.Estudiante.java: Nuestro pojo que por la simplicidad del ejemplo solo tendra los campos asociados a la tabla con la que trabajaremos.
package com.company.modelo; public class Estudiante { private Integer edad; private String nombre; private Integer id; public Integer getEdad() { return edad; } public void setEdad(Integer edad) { this.edad = edad; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } }
Nota: Podemos observar que solo tiene 3 campos ID, NOMBRE, EDAD que son casualmente los campos de nuestra tabla estudiantes en MYSQL.
com.company.dao.EstudianteDao.java: Definimos el contrato de los métodos que deberán incluir las clases que implementen esta interfaz.
package com.company.dao; import java.util.List; import javax.sql.DataSource; import com.company.modelo.Estudiante; public interface EstudianteDao { /* * Metodo utilizado para inicializar la conexion con la bd */ public void setDataSource(DataSource ds); public void Agregar(String nombre, Integer edad); public Estudiante getEstudiante(Integer id); public ListlistarEstudiantes(); public void Eliminar(Integer id); public void Actualizar(Integer id, Integer edad); }
Nota: Como particularidad debemos recalcar el método setdatasource que es por donde podremos suministrar el datasource de conexión con la base de datos y luego la definición de los métodos asociados a un CRUD.
com.company.dao.EstudianteJDBCTemplate.java: Es la implementacion dao, que logicamente implementa el codigo para las operaciones CRUD sobre la tabla estudiante.
package com.company.dao; import java.util.List; import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate; import com.company.modelo.Estudiante; public class EstudianteJDBCTemplate implements EstudianteDao { private DataSource dataSource; private JdbcTemplate jdbcTemplateObject; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; this.jdbcTemplateObject = new JdbcTemplate(dataSource); } public void Agregar(String nombre, Integer edad) { String SQL = "insert into estudiante (nombre, edad) values (?, ?)"; jdbcTemplateObject.update( SQL, nombre,edad); System.out.println("Registro creado nombre = " + nombre + " edad = " + edad); return; } public Estudiante getEstudiante(Integer id) { String SQL = "select * from estudiante where id = ?"; Estudiante student = jdbcTemplateObject.queryForObject(SQL, new Object[]{id}, new EstudianteMapper()); return student; } public ListlistarEstudiantes() { String SQL = "select * from estudiante"; List students = jdbcTemplateObject.query(SQL, new EstudianteMapper()); return students; } public void Eliminar(Integer id) { String SQL = "delete from estudiante where id = ?"; jdbcTemplateObject.update(SQL, id); System.out.println("Registro eliminado ID = " + id ); return; } public void Actualizar(Integer id, Integer edad) { String SQL = "update estudiante set edad = ? where id = ?"; jdbcTemplateObject.update(SQL, edad, id); System.out.println("registro actualizado ID = " + id ); return; } }
El código de la implementacion es la que nos permite indagar sobre las ventajas de spring sobre el manejo de JDBC.
Primero lo que debemos recalcar es la utilizacion de 2 variables privadas
La primera hace referencia al datasource de la base de datos que sera sostenida en la tabla
private DataSource dataSource;
La segunda hace referencia a la template para trabajar con JDBC que nos proporciona spring.
private JdbcTemplate jdbcTemplateObject;
El primer metodo que vamos a encontrar es el setDataSource que como parametro de ingreso recibe un datasource que lógicamente sera suministrado por inyección dado que este objeto esta precargado en el spring bean configuration que veremos mas adelante. En su interior el metodo asigna el valor a la variable privada para este fin, pero por otro lado genera una instancia de la template que nos proporciona spring pasandole la conexion con la base de datos para se encargue de ahora en mas.
Los métodos que realizan operaciones de actualización en la clase Agregar, Eliminar y Actualizar tienen una misma lógica de funcionamiento.
Primero definimos la cadena con la sentencia SQL indicando con ? la necesidad de un parámetro externo, ejemplo
insert into estudiante (nombre, edad) values (?, ?)
delete from estudiante where id = ?
update estudiante set edad = ? where id = ?
lo loco es que spring con solo hacer referencia al metodo update de la template , pasandole la query y los parametros que tiene que remplazar en la misma se encarga de todo.
sisi!!
yo pongo jdbcTemplateObject.update(query.., parametro1, parametro 2 .....parametro n); con esto spring se encarga de todo, es decir que si le paso una sentencia de insert va realizar un alta, si le paso una update realizara una actualizacion y si le paso una sentencia delete realizara una eliminacion.
ahora lo que llega es analizar los metodos de buscar un registro en particular el metodo getEstudiante y listarEstudiantes() donde la unica diferencia es que el primero retorna solo un objeto y el segundo retorna una lista de objetos, pero en su codigo no presentan casi ninguna diferencia dado que ambas realizan un procesamiento similar.
Para la busqueda de un registro utiliza el metodo queryForObject a quien le pasa la sentencia de consulta SQL, le pasa la generación de la instancia para el objeto de retorno y genera una instancia de la clase Mapper quien recibirá el resultado de la consulta y generara un objeto para cada fila del resulset que reciba que para este caso sera solo 1.
String SQL = "select * from estudiante where id = ?";
Estudiante student = jdbcTemplateObject.queryForObject(SQL,
new Object[]{id}, new EstudianteMapper());
Para la búsqueda de varios registros utiliza el método query a quien le pasa la sentencia SQL y una nueva instancia del objeto mapper que en este caso retorna una lista de objetos generada como producto de la generación de un objeto por cada fila del resulset resultante.
String SQL = "select * from estudiante";
List
new EstudianteMapper());
A mi modo de ver las cosas spring no hace otra cosa que lo que nosotros hacíamos antes de manera manual, por un lado generábamos una clase base que contenga método para operaciones de actualización y consulta y luego utilizábamos en las implementaciones la llamada a estos métodos para evitar código repetitivo y estos métodos ya tenían una gestión de excepciones propia ...etc la diferencia que ahora estas clases manuales te las brinda spring con la diferencia que están mucho mas cuidadas que quizás las que programábamos nosotros o quizás no, dado que la nuestra era propia acuerdo a nuestras necesidades. En el pasado hubiera significado que los programadores no tuviéramos que haber programado clases DAL propias para esta gestión.
com.company.dao.EstudianteMapper.java: Realiza el mapeo de cada fila de un resulset en un objeto del tipo estudiante identificado.
package com.company.dao; import java.sql.ResultSet; import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; import com.company.modelo.Estudiante; public class EstudianteMapper implements RowMapper{ public Estudiante mapRow(ResultSet rs, int arg1) throws SQLException { Estudiante student = new Estudiante(); student.setId(rs.getInt("id")); student.setNombre(rs.getString("nombre")); student.setEdad(rs.getInt("edad")); return student; } }
Nota: Recordemos que cuando usábamos un JDBC normal, después de hacer un
executeQuery()
, haciamos un while (rs.next())
y dentro del bucle haciamos un new a cada objeto por cada fila y lo agregábamos a una lista. Pues con el Spring es lo mismo, pero con la diferencia que con el resulset para cada fila genera un objeto en lista. src/main/resource/springjdbc.xml: Nuestro archivo de configuración de bean del proyecto.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/estudiante"/> <property name="username" value="root"/> <property name="password" value=""/> </bean> <bean id="EstudianteJDBCTemplate" class="com.company.dao.EstudianteJDBCTemplate"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
Nota: El archivo no presenta grandes novedades en primera instancia la declaración de nuestro dataource y la inyeccion del mismo en la clase EstudianteJDBCTemplate.
com.company.test.EstudianteTest.java: Nuestra clase de test del proyecto que es donde podremos ver el funcionamiento de las clases antes mencionadas.
package com.company.test; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.company.dao.EstudianteJDBCTemplate; import com.company.modelo.Estudiante; public class EstudianteTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("springjdbc.xml"); EstudianteJDBCTemplate studentJDBCTemplate =(EstudianteJDBCTemplate)context.getBean("EstudianteJDBCTemplate"); System.out.println("------Alta de registros--------" ); studentJDBCTemplate.Agregar("Zara", 11); studentJDBCTemplate.Agregar("Nuha", 2); studentJDBCTemplate.Agregar("Ayan", 15); System.out.println("------Listado de registros--------" ); Liststudents = studentJDBCTemplate.listarEstudiantes(); for (Estudiante record : students) { System.out.print("ID : " + record.getId() ); System.out.print(", Nombre : " + record.getNombre() ); System.out.println(", Edad : " + record.getEdad() ); } System.out.println("----Actualizando ID = 2 -----" ); studentJDBCTemplate.Actualizar(2, 20); System.out.println("----Listando registro ID = 2 -----" ); Estudiante student = studentJDBCTemplate.getEstudiante(2); System.out.print("ID : " + student.getId() ); System.out.print(", Nombre : " + student.getNombre() ); System.out.println(", Edad : " + student.getEdad() ); } }
Nota: Donde no hacemos nada raro de la habitual, pero genero el contexto apartir del spring bean configuración, segundo obtengo el bean EstudianteJDBCTemplate con el que ejecutaremos algunos de los metodos implementados en la clase para verificar su funcionamiento.
Analizando el resultado de ejecución:
El código del proyecto se lo puede descargar desde aquí. codigofuente.zip
Nota Final: Reduce gran cantidad de código repetido que tenia JDBC, me quita la responsabilidad de gestionar las excepciones por que lo realiza spring, me quita la responsabilidad de controlar las conexiones con la base de datos, me colabora con la generación de listas de objetos permitiendo un mapeo parcial con el contenido de la base de datos.
Listo me solucionaste todos los problemas por lo que migre a utilizar formas de acceso a la base de datos mas potentes HIBERNATE,.... YA FUE ME DECIDÍ LARGO TODO ESTO Y COMIENZO A DESARROLLAR CON ESTO!!! .mmm no hay chance JAJA si es verdad mejoro mucho el trabajo con JDBC pero no tiene comparacion en la facilidad que nos brindan estas grandes herramientas de trabajo, pero si es bueno tenerlo en cuenta cuando nos topamos con algún proyecto viejo que podríamos optimizar para no migrarlo o algun desarrollo pequeño para lo que HIBERNATE le quede grande.
Conociendo un poco de JdbcDaoSupport
Un plus seria Extends JdbcDaoSupport a nuestra clase de implementacion dao, dando basicamente le quitamos la responsabilidad a JdbcTemplate de gestionar la obtencion del datasource, dado que con solo inyectar el datasource a la clase de implementacion dao, jdbcDaoSupport se encargaria de manera automatica de la gestion del medio de dato.
Es decir este método en la clase de implementacion ya no seria necesario
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
Nota: Por lo que seguimos simplificando el código con el que trabajamos.
Conociendo callback RowCallbackHandler
¿Y si no hubiese que devolver ningún resultado? Por ejemplo, procesar una a una las filas del resultado y generar un informe con ellas. Para ello, Spring proporciona el callback rowCallbackHandler.
Cuando realizábamos una consulta por ejemplo utilizabamos el mapper para trabajar en el retorno, dado que en este caso retorno un objeto, pero si no retornara nada.??
String SQL = "select * from estudiante where id = ?";
Estudiante student = jdbcTemplateObject.queryForObject(SQL,
new Object[]{id}, new EstudianteMapper());
y una caso donde no retorno nada seria como lo siguiente.
jdbcTemplate.query("SELECT * FROM estudiante", new EstudianteRowCallbackHandler());
donde la clase seria una definición como la siguiente.
class EstudianteRowCallbackHandler implements RowCallbackHandler {
public void processRow(ResultSet rs) throws SQLException {
System.out.println("--Estudiante--");
System.out.println("Nombre: " + rs.getString(1));
System.out.println("edad: " + rs.getString(2));
}
}
y en la ejecución seria como si recorriéramos el resulset por consola y a veces utilizado cuando queremos ver que esta devolviendo la consulta sin que agreguemos ningún código para hacerlo.
Impresionante, sencillo y muy bien explicado, gracias a tu entrada pude comprender mejor a conocer lo que este interesante framework puede ofrecer. Sigue con tus geniales entradas, muchas gracias.
ResponderEliminarImpresionante, sencillo y muy bien explicado, gracias a tu entrada pude comprender mejor a conocer lo que este interesante framework puede ofrecer. Sigue con tus geniales entradas, muchas gracias.
ResponderEliminarMuy buen artículo, de gran calidad y muy bien explicado.
ResponderEliminarMuy buen artículo, de gran calidad y muy bien explicado.
ResponderEliminarMuy buena explicación gracias
ResponderEliminar