Pretender hacer la programación una actividad muy rentable, implica elegir bien el lenguaje, pienso que Java es una excelente elección.
Java lo utilizan las empresas mas grandes del mundo para desarrollar el core de sus negocios, por ejemplo, las empresas de telecomunicación, los bancos, empresas industriales, etc.
En este manual encontrarás información importante para poder programar bases de datos con JDBC. Este es el material que utilizo en el curso que imparto en SistemasUNI.
Como docente de programación, una de las preguntas que los estudiantes realizan con mucha frecuencia es:
¿Cómo empiezo el proyecto?
La mayoría que se inicia en programación, como es lógico, no tiene claro cómo debe iniciar su proyecto, esto se complica aún más cuando su primer profesor le indica que realice una ventana, y para programarla debe hacer doble click en el botón y empiece a programar.
Pienso, que una parte del problema está en que lo primero que se enseña a los futuros programadores es poner el código de la lógica de un requerimiento en el evento click de un botón, por lo tanto, creen que es así como se debe programar todas las ventanas que requiere su aplicación.
Este estilo de programación no creo que sea el más adecuado, tiene muchos problemas, como por ejemplo:
Repites bloques de código en varias partes de tu aplicación, esto dificulta su mantenimiento.
El mantenimiento de la aplicación rápidamente se vuelve complicado, en muy poco tiempo, tu aplicación se parece más al juego de Jenga.
Escalar tu aplicación, por ejemplo, de Cliente-Servidor a Web se hace prácticamente imposible.
Si cuando estas a la mitad de un proyecto, te cambian de motor de base de datos, actualizar el código se hace una tarea muy complicada.
Voy hacer referencia a Danny Thorpe:
Programar sin una arquitectura en mente es como explorar una gruta sólo con una linterna: no sabes dónde estás, dónde has estado ni a dónde vas.
Pienso que primero debemos pensar en una arquitectura, por ejemplo, pensar en dos capas, una capa de servicios (service) donde se implemente la solución del problema a resolver, y una capa para la interfaz de usuario (view).
Pensar en una capa de servicios para implementar la solución de un requerimiento o problema da muchas ventajas, entre las cuales tenemos:
Permite concentrarnos en la solución.
Facilita las pruebas, algo que no debes dejar de hacer.
Tu solución puedes escalarla fácilmente.
El mantenimiento del código es más fácil.
En el siguiente artículo estaré desarrollando un ejemplo ilustrativo.
CODIGO FUENTE
En esta sección te presento un video que una aplicación CLIENTE-SERVIDOR.
Tú tienes acceso al código fuente de esta aplicación, después del video tienes el enlace.
Cuando desarrollamos una aplicación con JDBC, una de las tareas que programamos frecuentemente es pasar un objeto de tipo ResultSet a una lista de objetos Map, List<Map<String,Object>>.
Por ejemplo, cuando queremos hacer una consulta a varias tablas, luego el resultado se debe mostrar en una tabla o quisas en un reporte con Jasper Report.
En este oportunidad desarrollara la clase JdbcUtil con un método que permite pasar un objeto ResultSet a una lista, la base de datos a utilizar es EurekaBank.
Las pruebas se realizan con 3 motores de bases de datos diferentes: Oracle, MySQL y SQL Server.
Para acceder a la metadata de un objeto ResultSet se utiliza el metodo getMetaData(), para obtener la cantidad de columnas se utiliza el método getColumnCount() de la metadata, para obtener el nombre de la columna se utiliza el método getColumnName(i) de la metadata, para obtener la etiqueta de la columna se utiliza el método getColumnLabel(i) de la metadata, siendo i el número de la columna e inicia en 1.
PRUEBA CON ORACLE
La versión de Oracle utilizada es la 11.2 y el driver jdbc utilizado es ojdbc6.jar.:
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Express Edition Release 11.2.0.2.0 - Production
PL/SQL Release 11.2.0.2.0 - Production
CORE 11.2.0.2.0 Production
TNS for 32-bit Windows: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production
El código base a utilizar es:
// Datos Oracle
String driver = "oracle.jdbc.OracleDriver";
String url = "jdbc:oracle:thin:@localhost:1521:XE";
String user = "eureka";
String pass = "admin";
// Conexión
Class.forName(driver).newInstance();
cn = DriverManager.getConnection(url, user, pass);
// Consulta
String sql = "aquí debe ir la consulta";
PreparedStatement pstm = cn.prepareStatement(sql);
ResultSet rs = pstm.executeQuery();
// Obtener metadata
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
System.out.println("getColumnName()\tgetColumnLabel()");
for (int i = 1; i <= columns; i++) {
System.out.println(md.getColumnName(i) + "\t" + md.getColumnLabel(i));
}
rs.close();
pstm.close();
Consultando un tabla
La consulta a utilizar es la siguiente:
select
chr_cliecodigo, vch_cliepaterno,
vch_cliematerno, vch_clienombre
from cliente
select
chr_cliecodigo cod, vch_cliepaterno pat,
vch_cliematerno mat, vch_clienombre nom
from cliente
El resultado es el siguiente:
getColumnName() getColumnLabel()
COD COD
PAT PAT
MAT MAT
NOM NOM
Consultando dos tablas
La consulta a utilizar es la siguiente:
select
tm.vch_tipodescripcion tipo,
sum(m.dec_moviimporte) importe
from tipomovimiento tm join movimiento m
on tm.chr_tipocodigo = m.chr_tipocodigo
group by tm.vch_tipodescripcion
El resultado es el siguiente:
getColumnName() getColumnLabel()
TIPO TIPO
IMPORTE IMPORTE
De los resultados obtenidos se puede concluir que tanto getColumnName() y getColumnLabel() arrojan los mismos valores, se puede utilizar cualquiera de los dos métodos.
PRUEBA CON MYSQL
La versión de MySQL utilizada es la 5.6 y el driver jdbc utilizado es la versión 5.1.23:
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.12-log MySQL Community Server (GPL)
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective owners.
El código base a utilizar es:
// Datos MySQL
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/EUREKABANK";
String user = "eureka";
String pass = "admin";
// Conexión
Class.forName(driver).newInstance();
cn = DriverManager.getConnection(url, user, pass);
// Consulta
String sql = "aquí debe ir la consulta";
PreparedStatement pstm = cn.prepareStatement(sql);
ResultSet rs = pstm.executeQuery();
// Obtener metadata
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
System.out.println("getColumnName()\tgetColumnLabel()");
for (int i = 1; i <= columns; i++) {
System.out.println(md.getColumnName(i) + "\t" + md.getColumnLabel(i));
}
rs.close();
pstm.close();
Consultando un tabla
La consulta a utilizar es la siguiente:
select
chr_cliecodigo, vch_cliepaterno,
vch_cliematerno, vch_clienombre
from cliente
select
chr_cliecodigo cod, vch_cliepaterno pat,
vch_cliematerno mat, vch_clienombre nom
from cliente
El resultado es el siguiente:
getColumnName() getColumnLabel()
chr_cliecodigo cod
vch_cliepaterno pat
vch_cliematerno mat
vch_clienombre nom
Consultando dos tablas
La consulta a utilizar es la siguiente:
select
tm.vch_tipodescripcion tipo,
sum(m.dec_moviimporte) importe
from tipomovimiento tm join movimiento m
on tm.chr_tipocodigo = m.chr_tipocodigo
group by tm.vch_tipodescripcion
El resultado es el siguiente:
getColumnName() getColumnLabel()
vch_tipodescripcion tipo
importe importe
De los resultados obtenidos se puede concluir que getColumnLabel() sería la opción mas conveniente a utilizar.
PRUEBA CON SQL SERVER
La versión de SQL Server utilizada es la 2008 R2 y el driver jdbc utilizado es JTDS versión 1.2.5:
Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64)
Apr 2 2010 15:48:46
Copyright (c) Microsoft Corporation
Enterprise Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1)
El código base a utilizar es:
// Datos SQL Server
String driver = "net.sourceforge.jtds.jdbc.Driver";
String url = "jdbc:jtds:sqlserver://localhost:1433/EUREKABANK";
String user = "sa";
String pass = "sql";
// Conexión
Class.forName(driver).newInstance();
cn = DriverManager.getConnection(url, user, pass);
// Consulta
String sql = "aquí debe ir la consulta";
PreparedStatement pstm = cn.prepareStatement(sql);
ResultSet rs = pstm.executeQuery();
// Obtener metadata
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
System.out.println("getColumnName()\tgetColumnLabel()");
for (int i = 1; i <= columns; i++) {
System.out.println(md.getColumnName(i) + "\t" + md.getColumnLabel(i));
}
rs.close();
pstm.close();
Consultando un tabla
La consulta a utilizar es la siguiente:
select
chr_cliecodigo, vch_cliepaterno,
vch_cliematerno, vch_clienombre
from cliente
select
chr_cliecodigo cod, vch_cliepaterno pat,
vch_cliematerno mat, vch_clienombre nom
from cliente
El resultado es el siguiente:
getColumnName() getColumnLabel()
cod cod
pat pat
mat mat
nom nom
Consultando dos tablas
La consulta a utilizar es la siguiente:
select
tm.vch_tipodescripcion tipo,
sum(m.dec_moviimporte) importe
from tipomovimiento tm join movimiento m
on tm.chr_tipocodigo = m.chr_tipocodigo
group by tm.vch_tipodescripcion
El resultado es el siguiente:
getColumnName() getColumnLabel()
vch_tipodescripcion tipo
importe importe
De los resultados obtenidos se puede concluir que ambos metodos arrojan los mismos resultados, por lo tanto, se puede utilizar cualquiera de los dos.
CLASE UTILITARIA
A continuación tenemos la clase propuesta para pasar un objeto ResultSet a una List<Map<String,?>>.
package pe.egcc.app.util;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author Eric Gustavo Coronel Castillo
* @blog gcoronelc.blogspot.com
*/
public final class JdbcUtil {
private JdbcUtil() {
}
public static List<Map<String, ?>> rsToList(ResultSet rs) throws SQLException {
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
List<Map<String, ?>> results = new ArrayList<Map<String, ?>>();
while (rs.next()) {
Map<String, Object> row = new HashMap<String, Object>();
for (int i = 1; i <= columns; i++) {
row.put(md.getColumnLabel(i).toLowerCase(), rs.getObject(i));
}
results.add(row);
}
return results;
}
}
A continuación se tiene un ejemplo de como utilizar esta clase:
List<Map<String,?>> lista = JdbcUtil.rsToList(rs);
Siendo rs un objeto ResultSet.
Puede descargar el proyecto desde el siguiente enlace: Descargar Proyecto
CÓDIGO FUENTE
En esta sección te presento un video que una aplicación CLIENTE-SERVIDOR desarrollada con Java y Oracle.
Tú tienes acceso al código fuente de esta aplicación, después del video tienes el enlace.
En esta oportunidad les traigo una guía práctica para crear copias de seguridad y sus restauración utilizando diferentes situaciones.
GUIA
CÓDIGO FUENTE - EUREKA-WEB-ORACLE-JDBC
En esta oportunidad te presento un video donde te explico cómo ejecutar el código fuente de una aplicación Java Web, utilizando HTML, CSS, JavaScript, AJAX y JSON, en la capa de persistencia se utiliza JDBC y base de datos Oracle XE 11g.
Tú tienes acceso al código fuente de esta aplicación, después del video esta el enlace.
PROGRAMACIÓN DE BASES DE DATOS ORACLE CON JAVA JDBC
Aprenderás a aplicar correctamente el API JDBC de Java para programar bases de datos ORACLE.
Aprenderás los conceptos fundamentales de Oracle Database y a crear el esquema de trabajo que se utilizará durante el curso.
Estarás capacitado para aplicar el API JDBC de Java para ejecutar consultas sin parámetros, consultas con parámetros, gestión de transacciones y ejecutar procedimientos almacenados que retornan cursor y que gestionan transacciones.
Estarás capacitado para desarrollar una aplicación de escritorio empresarial que ayude a las empresas a gestionar sus procesos comerciales.
En esta oportunidad te presento un video donde te explico cómo ejecutar el código fuente de una aplicación Java Web, utilizando HTML, CSS, JavaScript, AJAX y JSON, en la capa de persistencia se utiliza JDBC y base de datos Oracle XE 11g.
Tú tienes acceso al código fuente de esta aplicación, después del video esta el enlace.
En esta oportunidad te presento un video donde te explico cómo ejecutar el código fuente de una aplicación Java Web, utilizando HTML, CSS, JavaScript, AJAX y JSON, en la capa de persistencia se utiliza JDBC y base de datos Oracle XE 11g.
Tú tienes acceso al código fuente de esta aplicación, después del video esta el enlace.
Las colecciones son un conjunto de interfaces, clases abstractas y clases concretas que te permiten manejar una gran cantidad de datos relacionados en forma de listas para lo cual dispones de la interfaz List y la clase ArrayList, también como pares de datos CLAVE->VALOR para los cual dispones de la interfaz Map y la clase HashMap.
Todas las clases que nos permiten manejas conjuntos de datos se agrupan en un marco de trabajo conocido como Java Colecction Framework (JCF), y entre sus características la que mas resalta es que soporte Generics, esto quiere decir que podemos crear por ejemplo lista genéricas de tipo Object o listas personalizadas, por ejemplo de tipo Producto, Cliente, Cuenta, etc.
Una de sus aplicación la tenemos en la capa DAO, por ejemplo, si estamos consultan los productos de una categoría, la capa DAO estaría retornando una lista con objetos de tipo Producto.
Todos los componentes de JCF se encuentran en el paquete java.util.
Es un modelo basado en la cooperación e interacción de dos partes conocidas como servidor o back-end y cliente o front-end.
Aplicación Servidor
Es la aplicación que provee servicios, es la aplicación que provee los servicios; por ejemplo, los servidores de base de datos ofrecen servicios de persistencia de datos, podríamos mencionar a SQL Server, Oracle, MySQL, etc,
Aplicación Cliente
Es la aplicación que hace uso o consume los servicios de la Aplicación Servidor; por ejemplo, las aplicaciones comerciales como los sistemas de ventas y compras necesitan que sus datos persistan en el tiempo, para lo cual se recurren a los servidores de base de datos que ofrecen estos servicios.
Arquitectura Cliente-Servidor
El cliente se encuentra del lado del usuario y se define como un proceso consumidor de servicios, mientras que el servidor provee los servicios requeridos y se encuentra de manera remota al usuario y es transparente al cliente.
Los clientes deben estar en la red de la empresa, estas pueden ser redes locales, pero también es posible tener clientes remotos a través por ejemplo de una red VPN.
El API JDBC: Implementaciones
API JDBC
Esta API está compuesta por un conjunto de clases e interfaces que estandarizan el acceso a las bases de datos. Gracias a la utilización de JDBC, un programa Java puede acceder a cualquier base de datos sin necesidad de modificar la aplicación. Sin embargo, para que esto sea posible es necesario que el fabricante ofrezca un driver que cumpla la especificación JDBC.
Tipos de Driver
Tenemos cuatro tipos de driver:
Tipo 1: JDBC-ODBC bridge driver
Tipo 2: Native API/Partly Java Driver
Tipo 3: Pure Java Driver
Tipo 4: Native Protocol Java Driver
Tipo 1: JDBC-ODBC bridge driver
Permite utilizar drivers ODBC, su desventaja es que se debe instalar el driver ODBC en cada cliente.
Tipo 2: Native API/Partly Java Driver
Requiere que se instalen las librerías nativas en cada cliente.
Tipo 3: Pure Java Driver
Este tipo de driver traduce llamadas JDBC en un protocolo de red independiente del DBMS y luego, a un protocolo de DBMS.
Un Servidor JDBC, realiza la tarea de middleware, siendo capaz de conectar un cliente Java a diferentes bases de datos.
Tipo 4: Native Protocol Java Driver
El driver tipo 4 convierte llamadas JDBC directamente en el protocolo de red usado por el DBMS. Esto permite llamadas directas desde la máquina del cliente al servidor del DBMS, es una solución muy práctica y la más utilizada.
El API JDBC: Componentes Principales
Objeto: Connection
Establece la conexión con la base de datos y maneja las transacciones.
Objeto: Statement
Se utiliza para ejecutar sentencias sin parámetros.
Objeto: PreparedStatement
Se utiliza para ejecutar sentencias con parámetros.
Objeto: CallableStatement
Se utiliza para ejecutar procedimientos almacenados.
Objeto ResultSet
Se utiliza para procesar resultados.
Estrategias para programar transacciones
Controladas desde el cliente
En este caso desde la aplicación java programamos el inicio y fin de la transacción.
Controladas en la base de datos
En este caso programamos la transacción en el procedimiento almacenado.
El patrón DAO
Desarrollo Clásico
En el objeto de negocio se programa la lógica de negocio y la lógica de persistencia, haciendo difícil su mantenimiento.
Patrón DAO – División en Capas
El patrón DAO permite dividir en capas separadas la lógica de negocio y la lógica de persistencia.
Patrón DAO – Estructura
La capa de negocio hace uso de la capa de persistencia, y para que se comuniquen los datos se utilizan objetos Transfer Object (TO), también denominados Data Transfer Object (DTO).
Por ejemplo, si se consulta los datos de un cliente, el objeto DAO devolverá un objeto TO con los datos del cliente.
Si se consulta los artículos de una categoría, el objeto DAO devolverá una colección de objetos TO de tipo Artículo.
Patrón DAO – Diagrama se secuencia
En el diagrama de secuencia se puede apreciar la responsabilidad de cada capa, la capa Data Source puede ser un motor de base de datos, como por ejemplo Oracle, MySQL o SQL Server.
PARTE II - DOMINANDO AL MONSTRUO
Modelo de Datos
Creación del Esquema de Datos
El siguiente video ilustra la creación del esquema VENTAS.
Conexión con la Fuente de Datos
public class AccesoDB {
private AccesoDB() {
}
public static Connection getConnection() throws SQLException{
Connection cn = null;
try {
// --------------------------------------------------
// Paso 1: Cargar el driver a memoria
Class.forName("oracle.jdbc.OracleDriver").newInstance();
// Paso 2: Obtener el objeto Connection
String url = "jdbc:oracle:thin:@localhost:1521:XE";
cn = DriverManager.getConnection(url, "ventas", "admin");
// --------------------------------------------------
} catch (SQLException e) {
throw e;
} catch(ClassNotFoundException e){
throw new SQLException("No se encontró el driver de la base de datos.");
} catch(Exception e){
throw new SQLException("No se puede establecer la conexión con la base de datos.");
}
return cn;
}
}
Implementación de un CRUD
Para la demostración se implementa el CRUD para la tabla PRODUCTO.
Interfaz
public interface ProductoDao {
/**
* Transacción controlada desde el cliente
*
* @param prod
*/
void create1(Producto prod);
/*
* Transacción controlada en la Base de Datos
*/
void create2(Producto prod);
List readAll();
Producto readForId(int id);
List readForName(String name);
void update(Producto prod);
void delete(int id);
}