Hola
buenas noches a todos, este es mi primer post en el blog e iniciare con un tema
sobre persistencia básica en Java.
Cuando
abordamos el desarrollo de una aplicación en Java, uno de los primeros
requerimientos que debemos resolver es la integración con una base de datos
para guardar, actualizar y recuperar la información que utiliza nuestra
aplicación.
Se
llama “persistencia” de los objetos a su capacidad para guardarse y recuperarse
desde un medio de almacenamiento. La persistencia en Base de Datos relacionales
se suele implementar mediante el desarrollo de funcionalidad específica
utilizando la tecnología JDBC o mediante frameworks que automatizan el proceso
a partir de mapeos (conocidos como Object Relational Mapping, ORM) como es el
caso de Hibernate.
Si
bien existen más alternativas de persistencia, en este tutorial abordaremos
estas dos alternativas ya que son las más frecuentemente utilizadas.
JDBC
Java
DataBase Connectivity es el API de Java que define como una aplicación cliente
accederá a una base de datos, independientemente del motor de base de datos al
que accedamos.
A
continuación mostramos un ejemplo del código necesario para insertar un
elemento y hacer una consulta:
Class.forName(jdbcDriver);
// Crear una conexión
Connection con =
DriverManager.getConnection(jdbcUrl, userName,password);
//
Crear un Statement para obtener el máximo id
Statement stmt =
con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT MAX(id) FROM " + schema + "DEMO_QUERIES");int id = 0;
if rs.next()) {
id = rs.getInt(1) + 1;
}
rs.close();
stmt.close();
// Crear un PreparedStatement para insert
PreparedStatement
prepareInsert = con.prepareStatement(
"INSERT
INTO " +
schema + "DEMO_QUERIES (id, nombre, fecha)” +
“VALUES (?, ?, ?)" );// Completar sus atributos
Int i = 1;
prepareInsert.setInt(i++, id);prepareInsert.setString(i++, "Ejemplo JDBC");
prepareInsert.setDate(i++, new Date((new Date()).getTime()));
// Ejecutar el insert
prepareInsert.executeUpdate();
prepareInsert.close();// Crear un PreparedStatement para select
PreparedStatement
prepareSelect = con.prepareStatement(
"SELECT id, nombre, fecha FROM
" + schema + "DEMO_QUERIES
WHERE fecha < ?");// Completar sus atributos
prepareSelect.setDate(1,
new Date((new
java.util.Date()).getTime() + DAY_IN_MILLIS));
//
Ejecutar la select
rs =
prepareSelect.executeQuery();
while(rs.next()) {System.out.println(
"Id = " + rs.getInt(1) + " - nombre = " + rs.getString(2) + " - fecha = " + rs.getDate(3) + "");
}
rs.close();
prepareSelect.close();
Como
vemos el código es esencialmente simple aunque si tenemos un número amplio de
clases y problemáticas de maestro/detalle (como pueden ser facturas con items)
o soporte multi-base de datos la implementación puede volverse muy difícil de
mantener.
Una
mejora a la mantenibilidad es utilizar el patrón de diseño Data Access Object
(DAO, Objeto de Acceso a Datos ver http://es.wikipedia.org/wiki/Data_Access_Object) donde básicamente definimos una
interfaz y una clase que concentren toda la funcionalidad de creación, lectura,
actualización y borrado en la base de datos.
Hibernate
En
Hibernate esta misma funcionalidad se simplifica a:
entidad.setId(id);
entidad.setNombre( "Ejemplo Hibernate\n");
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
session.save(entidad);
session.getTransaction().commit();
Session session =
sessionFactory.getCurrentSession();
session.beginTransaction();
Query q =
session.createQuery("from e in class
com.persistencia.hibernate.Entidad where e.fecha < :fecha");
// se inyecta el valor del parámetro utilizando el nombre
q.setParameter("fecha", new
java.sql.Date(fecha.getTime()));
List
entidades = q.list();
¿¡¿Pero
cómo funciona la magia?!? Bueno, Entidad es un POJO (Plain Old Java Object), es
decir una simple clase Java que tiene métodos get y set para cada uno de los
atributos; así que ahí no está la magia.
Es
en el fichero de mapeo donde ponemos la magia, que tampoco es tan complicada:
<class name="com.hemasoft.demos.queries.hibernate.Entidad" table="DEMO_QUERIES">
<id name="id" type="java.lang.Integer" />
<property name="nombre" />
<property name="fecha" type="java.sql.Date" />
</class>
</hibernate-mapping>
Este
fichero de mapeo lo declaramos en hibernate.cfg.xml junto a la información de
acceso a la base de datos de la siguiente forma:
<hibernate-configuration>
<session-factory>
<!-- Database
connection settings -->
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@192.168.1.20:1521:qemu</property>
<property name="connection.username">test</property>
<property name="connection.password">test</property>
<!-- JDBC
connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect
-->
<property name="dialect">org.hibernate.dialect.Oracle9Dialect</property>
<mapping
resource="com/hemasoft/demos/queries/hibernate/Entidad.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Creo
que el fichero es lo suficientemente intuitivo como para no necesitar mayores
explicaciones. Los costes de aprendizaje de este framework en términos de
tiempo dedicado se van recompensando desde el primer día con el ahorro en
tiempo de desarrollo y depuración de código JDBC. Incluso, a partir de la
versión 3 de Hibernate su configuración se simplifica notablemente mediante
Anotaciones (recomiendo ver http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#entitymapping).
Además,
Hibernate nos proporciona grandes beneficios como:
·
soporte
a múltiples motores de base de datos.
·
bajo
acoplamiento entre negocio y persistencia, ya que su diseño está orientado a
objetos así como el soporte a consultas y operaciones (HQL).
·
desarrollo
robusto, ya que el framework ha madurado tras años de uso en decenas de miles
de proyectos.
·
optimizado,
ya que el SQL generado contiene optimizaciones específicas para cada motor de
base de datos mediante componentes especializados llamados dialectos.
·
rápido
y completo, ya que con la funcionalidad estándar de Hibernate podremos cubrir
el 80 - 90% de la persistencia de nuestra aplicación.
Todo
esto nos permite centrar nuestros esfuerzos en desarrollar la funcionalidad de
la aplicación.
Conclusiones
El
acceso mediante JDBC conviene utilizarlo cuando tenemos pocas clases, escasos
conocimientos, escaso tiempo para formación, modelo de datos muy desnormalizado
o alguna otra razón de peso.
Para
todo lo demás, Hibernate es una solución madura y dinámica que nos permite
simplificar a la vez que robustecer nuestro acceso a bases de datos.
Espero
que les sea de utilidad, nos vemos en una próxima oportunidad.
Para
más información diríjase al siguiente enlace: http://www.autentia.com