Hola a todos.
El día de hoy les traigo una librería que en cuanto la conocí me pareció una herramienta bastante útil para el momento de hacer consultas para acceder a la información de la base de datos, sin pasar por los mapeos ni de Spring JDBC (Mappers, ResultSet, etc) ni de Spring ORM (Hibernate, JPA, etc).
La librería es la Apache Commons DbUtils.
http://commons.apache.org/dbutils//index.html
Como lo dice su misma introducción, Commons DbUtils es conjunto de clases orientadas a facilitar el trabajo con JDBC.
Algunas de las ventajas de utilizar DbUtils son:
- No hay posibilidad de fuga de recursos. Codificar consultas JDBC no es difícil, pero es lento y tedioso. Esto conduce a menudo a las fugas de conexión que pueden ser difíciles de localizar. Aunque este objetivo también lo cumple a cabalidad Spring JDBC sin ningún contratiempo.
- Código de persistencia más claro. La cantidad de código necesario para guardar los datos en una base de datos se reduce muchísimo. El código expresa claramente su intención, sin la invasión de código de limpieza de recursos.
- Puede llenar automáticamente las propiedades de JavaBean desde los ResultSet. No es necesario asignar manualmente los valores de las columnas de las tablas a las propiedades de los beans a través de los métodos setter. Se puede hacer de manera directa con una gran mayoría de tipos de datos de Java.
Dentro de su misma página podemos encontrar varios ejemplos:
http://commons.apache.org/dbutils//examples.html
Las clases más importantes en DbUtils son QueryRunner y el ResultSetHandler. No es necesario saber más para usarlo, pero siempre puedes revisar la documentación y la API de la librería.
La clase QueryRunner será la que nos proporcione todos los métodos templates para realizar las consultas a las bases de datos.
El método que veremos en este post será el método query, el cual recibirá el query, el ResultSetHandler y los parámetros de nuestra consulta.
¿Y a todo esto que es el ResultSetHandler?
Es la interface de la librería que nos brindará las implementaciones necesarias para poder “mapear” nuestros resultados hacia el tipo de objetos que necesitemos. En este post usaremos dos implementaciones: una que nos permita mapear directamente a objetos java.util.Map y otro que nos permita mapear directamente a objetos de nuestro negocio.
Las implementaciones que nos brinda la librería son:
AbstractKeyedHandler, AbstractListHandler, ArrayHandler, ArrayListHandler, BeanHandler, BeanListHandler, BeanMapHandler, ColumnListHandler, KeyedHandler, MapHandler, MapListHandler,ScalarHandler
Con solo leer los nombres podemos saber a que tipo de objetos podemos mapear directamente.
¿Pero cómo hacemos esos mapeos? ¿Cómo usamos los QueryRunner y ResultSetHandler? Ahora lo veremos.
Tenemos una tabla en una base de datos My SQL con varios tipos de datos:
La llenamos de información y ahora procedemos a crear un proyecto Maven desde nuestro IDE, en mi caso yo uso el Spring Tool Suite.
No es necesario crear un proyecto web, con uno simple nos basta:
Llenamos los datos:
Y ahora estas serán las dependencias que usaremos del Repositorio de Spring:
Remarco la que pertenece a la librería que estamos revisando commons-dbutils.
Ahora creamos la clase de negocio correspondiente a la tabla que creamos:
Para este ejemplo solo haremos dos consultas una en la que obtendremos un listado de Maps y otra un listado de Productos, como comentamos en líneas anteriores.
Como usaremos Spring como contenedor, primero crearemos la interface de la capa de acceso a datos con los métodos indicados:
Y ahora empezaremos a usar la librería. Particularmente prefiero crear una clase de soporte de la cual van a heredar todas mis implementaciones de DAOs.
Creamos la clase DBCPDaoSupport, la cual tendrá el método más importante: executeQuery(…). Este método será usado por otros métodos utilitarios para ejecutar las consultas a la base de datos. Sus parámetros son:
- String sql: esta será la consulta que se requiera ejecutar.
- Object[] filterkeys: los filtros de nuestra consulta.
- ResultSetHandler: aparte del query, este es el parámetro más importante. Este le dirá a la librería contra que deseamos mapear los resultados de nuestra consulta.
La clase QueryRunner es la encargada de finalmente ejecutar la consulta. Esta necesita el DataSource de la aplicación, es decir, el objeto que tenga toda la información para el acceso a la base de datos. El cual debe estar en alguno de nuestros archivos de configuración de nuestra aplicación. Más adelante veremos donde, por ahora muestro como debería ser:
Cabe mencionar que estoy haciendo heredar a DBCPDaoSupport de la clase JdbcDaoSupport, pues esta hace un uso eficiente de los recursos, entre ellos el DataSource, que como se vé será usado por la clase QueryRunner.
Creamos una instancia de la clase QueryRunner y le asignamos el DataSource. Una vez tenemos lista la instancia ejecutamos el query.
Dentro de nuestra clase utilitaria, crearemos el primer método utilitario que nos permitirá mapear los resultados de nuestras consultas sobre Maps de Java:
Lo resaltante de aquí es la clase MapListHandler la cual es quien se encargará de hacer el mapeo de cada fila del resultado contra un objeto java.util.Map. Esta clase implementa la interface ResultSetHandler, es por ello que el método executeQuery lo acepta.
Ahora procedemos a crear nuestra implementación de la interface ProductoDao. Creamos la implementación, la hacemos heredar de DBCPDaoSupport e implementar ProductoDao, la marcamos como bean de Spring y le asignamos su dependencia:
Luego implementamos el primer método de la interface, el cual devolverá una lista de productos en objetos java.util.Map. Y para ello usamos nuestro método findListOfMaps.
Para probar que hace y si está correcta nuestra implementación crearemos test cases que nos permitan probar lo implementado. Primero creamos nuestro archivo de configuración de Spring para el ambiente de pruebas:
Como se puede observar aquí es donde se tendrá el bean del DataSource declarado.
Luego procedemos a crear nuestro test case:
Haciendo uso de un Breakpoint, podemos observar que nos devuelve la consulta al ser ejecutada con el método findListOfMaps(…):
Efectivamente nos devuelve un java.util.Map por cada registro encontrado en la base de datos. ¡Y la ejecución es exitosa!
Si quisieramos obtener los resultados de las columnas, deberiamos acceder a ellas a través de los Maps y con nombre de llave igual al nombre de las columnas de la tablas. De la siguiente forma:
Dentro de nuestra clase utilitaria, crearemos el segundo método utilitario que nos permitirá mapear los resultados de nuestras consultas sobre objetos de nuestra clase de negocio Producto:
Lo resaltante de aquí es la clase BeanListHandler la cual es quien se encargará de hacer el mapeo de cada columna de cada fila del resultado contra un atributo de la clase. Para ello debemos pasarle la clase contra la cual queremos hacer el mapeo.
Al igual que el caso anterior, BeanListHandler implementa la interface ResultSetHandler, es por ello que el método executeQuery lo acepta.
Ahora creamos la implementación del método obtenerListaDeProductos() usando el método findListOfBeans al cual pasamos el query y la clase Producto:
Es importante ver que he usado alias para mapear los resultados de la consulta. Esto se debe a que la libreria usará dichos alias para asignar los resultados a las propiedades con el mismo nombre del alias:
Así, si es que deseamos que los valores obtenidos de la columna fecha_creacion se asignen al atributo fechaCreacion, en nuestro query debemos usar “fecha_creacion AS fechaCreacion”:
Agregamos el método al test case:
Lo ejecutamos y verificamos que arroja en los resultados:
Se puede observar claramente que el mapeo es directo, incluso en el campo fechaCreacion que es de tipo Date y enOferta de tipo boolean. Los resultados nuevamente son exitosos:
Como pueden ver Apache Commons DbUtils es una herramienta útil y muy sencilla de usar y aprender. Siempre se le puede dar una oportunidad.
Asimismo, hay que tomar en cuenta que es una alternativa a la misma API de Java o a Spring JDBC. Cabe mencionar que este último también es capaz de mapear directamente a una lista de java.util.Map.
Espero la información les sea de utilidad y me comenten como les fue.
Para ustedes el código fuente :)



























5 Comments
Hola Susan, no me funciona con las dependencias mostradas, sino con estas.
org.springframework
spring-jdbc
3.1.0.RELEASE
Saludos
Hola Miguel.
Si estás usando el código fuente que he subido debería funcionar bien la descarga de librerias.
Sin embargo, si lo estás haciendo desde cero, sin ver mi código, debes apuntar al repositorio de Spring con los tags repositories en el pom.xml.
Me avisas cual de las dos cosas está sucediendo para poder ayudarte.
Saludos,
Susan
Consulta…
Si hubiera un campo más en la tabla, como por ejemplo:
- cantidad (int)
¿En el bean Producto, bastaría con agregar un atributo “cantidad” del tipo Integer ?
Si, Sasuke.
Tal como dice José, debería funcionar tal cual.
Con versiones antiguas de la libreria no se podia mapear contra Integer, pero ahora si.
Saludos,
Susan
Si sasuke nada mas.