Sunteți pe pagina 1din 45

Bases de Datos con Java

Libro 1:
Ttulo: Fundamentos de bases de datos con Java.
Autores: Varios
Ao de publicacin: 2001
Editorial en espaol: Ediciones Anaya Multimedia (Grupo
Anaya, S.A.)
Editorial original: Wrox

Libro 2:

Ttulo: Java 6.
Autor: Felipe Daz Lima
Ao de publicacin: 2010
Editorial en espaol: Ediciones Anaya Multimedia (Grupo
Anaya, S.A.)

Captulo 1: Introduccin
Cuando se trabaja con Java y se necesita trabajar con bases de datos,
se puede hacer a travs de la API JDBC. Este mecanismo o interfaz,
proporciona muchos objetos de Java para enviar datos entre las clases
Java y la BD. Aqu se conocern las clases e interfaces ms importantes
de JDBC.
Podra decirse que JDBC en Java es anlogamente igual a ADO.NET en
.NET.

1.1

Persistencia en Java

Existen varias formas de mantener datos persistentes en Java.


Algunos de los ejemplos incluyen el empleo de ficheros planos, la
serializaciones de objetos y el uso de una base de datos.
Dependiendo de la cantidad y el tipo de datos que sea necesario
hacer persistente, se elegir entre una u otra.
a. Ficheros planos
Podemos leer y escribir datos de ficheros planos que estn
almacenados como cualquier otro fichero del disco.
Esta opcin es viable cuando todo lo que hace falta guardar son
los valores de una configuracin, un documento de texto que se
imprimir ms adelante o un documento XML para transferirlo a
otra parte del mundo. Si estamos hablando de un pequeo
conjunto de datos que no se actualiza muy a menudo, el uso de
una base de datos puede ser una solucin demasiado compleja.
Si disponemos de algo ms que un pequeo conjunto de datos
estticos, el empleo de un fichero plano puede ser una mala
alternativa. Si se van a realizar peticiones sobre estos datos,
entonces recorrer el archivo para localizar los datos a leer y/o
actualizar puede ser muy costoso en trminos de memoria y
tiempo de ejecucin. Adems no existe forma natural o lgica de
relacionar la informacin de distintos archivos. Se podra crear
una clave para buscar en otro fichero, pero la bsqueda a travs
de mltiples ficheros planos sera muy poco eficaz.
b. Serializacin de objetos
Para gestionar la situacin en la que necesitamos almacenar el
estado del sistema, Java dispone de la posibilidad de hacer un
objeto serializable. Hacer un objeto serializable simplemente
quiere decir que queremos ser capaces de escribir el objeto a
travs de algn canal y de leerlo ms tarde.

Ejemplos:
Envi de la salida de un programa a un archivo del disco o a una
conexin de red con otro ordenador. Cuando definimos clases,
solo ser necesario que esas clases implementen el interfaz
java.io.Serializable
c. Bases de datos relacionales
Es un conjunto de objetos, de entidades. Estos objetos controlan
la forma en la que se almacenan y gestionan los datos.

1.2

SQL

SQL es un lenguaje informtico para comunicarnos con bases de


datos.
Los elementos que se comunicaran sern normalmente un
programa cliente que enviara peticiones SQL a travs de una
conexin a un servidor que almacena los datos.
Al contrario de Java que es un lenguaje procedural, SQL es un
lenguaje declarativo, es decir no se especifica cmo se realizar
tal tarea sino expresa que es lo que queremos hacer y el RDBMS
decide la mejor manera de realizarlo.

1.3

Como interacta Java con bases de datos

Cada fabricante de base de datos relacionales ofrece sus propios


API y herramientas de desarrollo para crear aplicaciones con su
base de datos. Estas bases de datos son todo menos estndares.
Ahora, hasta este momento tenemos un lenguaje estndar llamado
SQL que permite realizar consultas a una base de datos relacional.
Lo que hace falta es un lenguaje de programacin que cumpla con
2 requisitos:
Que permita construir aplicaciones de base de datos que no
dependan de la plataforma en la que se est corriendo la base
de datos. Es decir, los desarrolladores necesitan escribir
aplicaciones que puedan correr en plataformas por ejemplo
Intel, Sun, AS/400, etc.
Que permita construir aplicaciones que se ejecuten en muchas
plataformas de base de datos. La idea es que un desarrollador
debe poder escribir la aplicacin una sola vez y usarla con otra
base de datos distinta con poco trabajo adicional.

Estos dos requisitos los cumple perfectamente Java con su API


JDBC.
JDBC
Java ofrece un API de bases de datos estndar llamado JDBC
que permite que el programador escriba aplicaciones con un
interfaz comn que no dependa de la base de datos. El
desarrollador de software escribe para el API y no para la base
de datos que hay por debajo de l.
La librera Java DatabaseConectivity (JDBC) proporciona los
medios necesarios para efectuar la conexin a la BD,
consultas SQL y procesamiento de los resultados
obtenidos de una base de datos relacional.
Java es independiente de la plataforma, es decir un programa
100% Java escrito para un ordenador Windows se ejecutar sin
ser recompilado en una mquina Solaris Sparc, en una
Macintosh o en cualquier otro ordenador para el que exista una
mquina virtual Java. JDBC lleva esta posibilidad a las bases de
datos. Si escribimos un programa java con JDBC y contamos con
el driver de base de datos adecuado, ese programa podr
trabajar con cualquier base de datos sin que sea necesario
recompilarlo. Sin JDBC el cdigo Java tendra que contener
elementos de cdigo dependientes de la base de datos, lo que
va en contra de la filosofa de Java: Progrmalo una vez,
ejectalo donde quieras.

Un controlador o driver es la implementacin de la interfaz JDBC


adecuada a una base de datos concreta.
JDBC permite que escribamos cdigo Java y que dejemos el
cdigo dependiente de la base de datos para el driver. Es decir
basta con escribir un programa en Java que haga uso de la
biblioteca JDBC para enviar consultas SQL a cualquier origen de
datos. Por lo tanto, si cambiamos de BD, solo ser necesario
cambiar el driver empleado y ya estar todo listo parta
funcionar.
El API JDBC se dise para ser empleado con la mayor variedad
posible de bases de datos relaciones. Es decir se dise como
un interfaz para ejecutar consultas SQL y admite todos los
dialectos de SQL.

Con JDBC se puede acceder prcticamente a cualquier origen de


datos como una base de datos relacional, una hoja de clculo o
incluso un fichero plano.
SQLJ
SQLJ permite introducir sentencias SQL estticas directamente
dentro del cdigo Java. El API JDBC por otro lado, permite la
ejecucin de cdigo SQL dinmico.
SQLJ puede simplificar mucho el cdigo. En lugar de usar el API
JDBC para abrir conexiones, crear consultas, invocar mtodos
para ejecutar SQL y analizar el resultado, solo es necesario
escribir unas cuantas lneas de cdigo SQL para obtener el
mismo resultado. Eso s, SQLJ carece de flexibilidad motivo por
el cual JDBC sigue siendo el sistema preferido para acceder a
BDs en Java.

EJB
Las Enterprise Java Beans o EJBs, ofrecen otra forma de acceder a
la informacin de una base de datos en un entorno corporativo. Las
EJBs son un importante componente de Java2 Enterprise Edition.
Los dos tipos principales son:
Session beans:
Interactan con el usuario, reciben sus peticiones y devuelven
lo que pidi o envan la peticin a otra bean para acte.
Entity beans:
Se emplean para interactuar con la base de datos. Existen dos
implementaciones de entitybeans:
Container-ManagedPersistence (CMP)
Bean-managedPersistence (BMP)

Captulo 2: JDBC
El objetivo de este captulo en adelante es mostrar a grandes rasgos
que es y cmo funciona el API JDBC as como la forma de emplearlo para
conectar Java con bases de datos relaciones.
En este captulo, aprenderemos a conectarnos con una base de datos
mediante JDBC, a obtener informacin de una tabla de una base de
datos e incluso la forma de incluir sencillos mecanismos de control de
errores en el cdigo. Los puntos que se trataran son los siguientes:
Las distintas versiones de JDBC y las caractersticas principales de
cada uno.
Como cargar una clase Driver y registrarla con DriverManager.
Como realizar una conexin con base de datos Cloudscape y
Oracle con el mtodo getConnection().
Enviar una consulta a la base de datos con el objeto Statement.
Recibir los datos de la base de datos con un objeto Resultset
Como obtener metadatos de la base de datos con el mtodo
getMetaData().
Como reunir todos estos elementos en un sencillo programa para
obtener datos de columnas seleccionadas de una tabla de la base
de datos y tambin como obtener todos los datos de la tabla.
Tcnicas bsicas de gestin de errores en el cdigo JDBC.
2.1 SQL y JDBC
La librera o el API JDBC est implementada en el paquete java.sql y
javax.sql. Es decir en esos paquetes radican el conjunto de clases e
interfaces relacionadas a JDBC.

Al trabajar con esta API, podemos usar:


Una clase DriverManager para cargar un driver.
Un objeto Connection para establecer una conexin con la base
de datos
Un objeto Statement para encapsular la consulta SQL y
envirsela a la base de datos para que la lleve a cabo.
Un objeto ResultSet que almacenar el resultado de la
consulta.
Tcnicamente JDBC est definido como una interfaz para trabajar
con base de datos relacionales. Aunque es posible acceder a
orgenes de datos no relacionales, nos centraremos en los orgenes
de datos relacionales.
JDBC dispone de un interfaz distinto para cada base de datos, lo
que llamaremos driver. Esto permite que las llamadas a los
mtodos en Java de las clases de JDBC se correspondan con el API
de la base de datos.
Aplicacin en Java

JDBC

Sybase

Oracle

SQL Server

...

Figura 2.1: Como es que interacta una aplicacin Java con su API
JDBC y finalmente con las bases de datos.

2.2

Relacionar JDBC con ODBC

Uno de los fundamentos del diseo de JDBC es facilitar la creacin


de drivers JDBC basados en otros APIs de bases de datos. Existe

una relacin muy estrecha entre la arquitectura y el API de JDBC y


la de sus correspondientes elementos de ODBC, ya que todos ellos
estn basados en un mismo estndar. Estos son los puntos que
tienen en comn:
Driver Manager: Cargar los drivers de base de datos y gestiona
las conexiones entre la aplicacin y el driver.
Driver: Traduce las llamadas del API a operaciones para un
origen de datos concreto.
Connection: Una sesin entre una aplicacin y una base de
datos.
Statement: Una sentencia SQL que realiza una consulta o
actualizacin de datos.
Metadata:o Metadatos, es la informacin sobre los datos
encontrados, informacin sobre la base de datos, el driver, etc.
ResultSet: Conjunto de columnas y filas de datos resultado de
ejecutar una consulta.
Un aspecto fundamental es que JDBC se cre a partir de ODBC pero
que adems, tiene todas las ventajas de un API 100%,
especialmente la portabilidad. El grado de certeza con que usando
JDBC pueda hacerse un cambio de una base de datos depende del
tipo de Driver JDBC que se emplee y de si estn usando o no
extensiones propietarias de la base de datos. Tener en cuenta que
pueden existir hasta 4 tipos o clases de driver (mayor informacin
revisar libros Fundamentos de BD con Java y Java 6).

2.3

Versiones de JDBC

a. JDBC 1.x
b. JDBC 2.0 ao 2001
Con esta versin, el API se ofrece en dos partes:
El ncleo del API JDBC 2.0, implementado en el paquete
java.sql, que se incluye con java 2 SDK Standard Edition.
El paquete opcional del API JDBC 2.0, implementado en el
paquete javax.sql o que esta como parte del Java 2 SDK
Enterprise Edition.
El ncleo del API JDBC 2.0
Las nuevas caractersticas de JDBC 2.0 se pueden dividir en dos
categoras: nuevas capacidades y soporte para tipos de datos
avanzados. Las nuevas capacidades incluyen:

Conjuntos de resultados desplazables: ahora tanto


hacia atrs como hacia adelante y hacia una posicin
concreta.
Conjuntos de resultados actualizables: antes se
actualizaba con sentencias SQL. Ahora el objeto ResultSet
dispone de mtodos de la forma updateX.
Actualizaciones en bloque: ahora se permite sealar una
serie de actualizaciones a la BD como un grupo en vez de
enviarlas una por una. Es una mejora ya que reduce el
trfico por la red.
Ajuste del rendimiento: mejoras que permiten afinar el
funcionamiento de la BD para acelerar la consulta de filas.
El paquete opcional del API JDBC 2.0
Esta extensin al API aade funcionalidades que son
especialmente interesantes en entornos corporativos como las
siguientes:
DataSources
JNDI o Java Naming and Directory Interface
Pool de conexiones
Rowsets
Transacciones distribuidas
c. JDBC 3.0 ao 2002
d. JDBC 4.0 Especificada en el JSR 221 ao 20XX

2.4

Como funciona JDBC

La arquitectura JDBC est basada en un conjunto de clases e


interfaces de Java que permiten conectar con bases de datos, crear
y ejecutar sentencias SQL y recuperar y modificar datos de una
base de datos.

Figura 2.2: Figura que muestra las operaciones que se realizan


cuando el JDBC entra en funcionamiento.
Cada una de las cajas de la ilustracin representa un interfaz o
clase JDBC que tiene un papel fundamental en el acceso a una base
de datos relacional.
Si profundizamos la ilustracin, veremos los siguientes pasos:
1. Importar las clases necesarias
2. Cargar el driver JDBC
3. Identificar el origen de datos
4. Crear un objeto Connection
5. Crear un objeto Statement
6. Ejecutar una consulta con el objeto Statement
7. Recuperar los datos del objeto ResulSet
8. Liberar el objeto ResulSet
9. Liberar el objeto Statement
10.
Liberar el objeto Connection
Es decir, todo el trabajo con JDBC comienza con la clase
DriverManager, que es la responsable de establecer conexiones con
los orgenes de datos, a travs de los drivers JDBC.
Los drivers de BD JDBC se definen mediante clases que
implementan la interfaz Driver. Un driver JDBC sabe cmo convertir
las peticiones SQL para una base de datos concreta. Sin el driver
adecuado, no podramos conectarnos con una base de datos.
PASOS
PASO 1: Adjuntar el JAR del motor de BD con el cual se va a
trabajar
Normalmente desarrollaremos nuestros aplicativos en Java usando
NetBeans. De ser as y si tuviramos que trabajar con una BD, lo
primero que debemos de hacer luego de crear el nuevo proyecto,
debemos de ubicar el JAR o el driver de nuestro motor de BD con
el que trabajaremos. Ver figura 2.3 y 2.4.

Figura 2.3: Escogemos la opcin de Agregar archivo JAR y


ubicar el JAR o driver del motor BD que usaremos. Tambin
podemos escoger Agregar biblioteca si ya tuviramos creada
nuestra librera SQL Server apuntando hacia el JAR. En ambos
casos es lo mismo.

Figura 2.4: En caso trabajemos con SQL Server esa sera la


librera a usar.

PASO 2: Cargar el driver en memoria con Class.forName()


Se inicializa el Driver y se registra. Para ello hay varias opciones.
Una puede hacer un new del driver o bien instanciarlo con
Class.forName("nombre de clase"), que es como hacer el new,
pero de una forma rara.
Es decir, cargamos el driver adecuado para que nuestro cdigo
Java pueda establecer una conexin con la BD. Para conseguirlo,
emplearemos la clase JDBC java.sql.DriverManager, que
implementa la interfaz java.sql.Driver.
Existen dos maneras de cargar un Driver y registrarlo con
DriverManager:
Usar el mtodo Class.forName()
Identificar la clase Driver en la propiedad del sistema
jdbc.drivers
De momento usaremos la primera forma.
Para cargar al driver llamaremos al mtodo forName() de la clase
Class y le pasamos un objeto String como argumento con el
nombre de la clase del driver como argumento:
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Si estamos trabajando con NetBeans, ese nombre entre comillas lo
podemos sacar siguiendo la figura 2.5 y 2.6.
El mtodo forName() puede lanzar una excepcin del tipo
ClassNotFoundException si no puede encontrar la clase del
driver(por ejemplo, si el archivo que es cargado normalmente en
el nodo de libreras en NetBeans no estuviera). Por ende, el
mtodo forName() debe estar preparado para gestionar esa
excepcin es por eso que la llamada a este mtodo debe estar
dentro de un bloque try y catch.

Figura 2.5: Una vez seleccionado el motor de BD con el que


trabajaremos, hacemos clic derecho y escogemos la opcin
Personalizar. (En caso que no aparezca, simplemente hacemos clic
derecho en el icono Controladores, escogemos Nuevo
Controlador y por ultimo ubicamos el JAR o el driver JDBC que
queremos.)

Figura 2.6: Copiamos lo que muestre en Clase del Driver.


Cada clase Driver normalmente crear una instancia de s misma
cuando sea cargada y registrar esta instancia automticamente
con una llamada al mtodo RegisterDriver de la clase
DriverManager.
Nota:
1. No se puede crear objetos DriverManager porque su
constructor est declarado como private. Adems todos sus

mtodos de la clase DriverManager son static y operan


sobre toda la clase, no sobre otras instancias creadas.
2. Usando un driver posterior igual o superior a la versin 4 de
JDBC, ya no es necesario cargar la clase driver explcitamente
con forName() dado que si obtener la conexin con
DriverManager, este ya lo carga automticamente.
PASO
3:
Establecer
una
conexin
con
DriverManager.getConnection()
Luego de cargar y registrar el driver, necesitamos establecer la
conexin con la BD. El objeto Connection representa una
conexin con un origen de datos en concreto, adems permite
crear y ejecutar sentencias SQL.
Cuando es necesaria una conexin con un driver JDBC, no se
necesita crear un objeto que encapsule la conexin. Lo har la
clase DriverManager, la cual brinda varios mtodos static para
crear objetos que implementan la interfaz connection y que
encapsulan una conexin con la BD. Todos ellos son versiones
sobrecargadas del mtodo getConnection().
Es decir, JDBC brinda la interfaz Connection y el driver JDBC (en
este caso de SQL Server) brinda una clase que implementa la
interfaz Connection.
Existen 3 formas sobrecargadas del mtodo getConnection() en
la clase DriverManager que devuelven un objeto Connection.Una
de las formas sobrecargadas es la sentencia es la siguiente:
Connection con = DriverManager.getConnection(sourceURL,user,pass);

Ese es el mtodo sobrecargado con 3 parmetros que


normalmente usaremos:
a. user: muchas veces para entrar al motor de BD, lo hago a
travs de un nombre de usuario y contrasea. Por ejemplo un
usuario para MySQL es root y para SQL Server es sa
b. pass: hace referencia a la clave asignada al usuario del
punto b.
Nota:
En algunos casos el user y pass no son suficientes para
establecer una conexin y se necesita ms informacin o
permisos para crear la conexin. Para solucionar esto, la clase
DriverManager aporta otra forma de getConnection() que
acepta un objeto Properties como argumento y en este
objeto recin podemos incluir esa informacin faltante. Para

mayor detalle revisar el libro Base de Datos con Java,


editorial Wrox y Anaya, pgina 281.
c. sourceURL
La variable sourceURL es un objeto tipo String que identifica
la direccin donde est la BD, adems sourceURL tiene una
forma general que es para todas las bases de datos y es la
siguiente:

jdbc:<subprotocol>:<subname>
jdbc: Indica el protocolo. Adems indica que el URL
se refiere a un origen de datos JDBC.
<subprotocol> Identifica al motor de BD como SQL
Server, Oracle, MySQL. Adems identifica el driver JDBC
a usar.
<subname> Identifica la BD.
Por ejemplo:
String sourceURL =

"jdbc:sqlserver://localhost:1433;databaseName=BD_X;
<subprotocol> En este caso es SQL Server. Si
trabajamos con un driver Oracle, el subprotocol ser
Oracle.
<subname> Le dice al driver que la BD est ubicada
en el localhost por el puerto 1433y se llama BD_X
El contenido de la variable sourceURL se puede obtener como se
ve en la figura 2.7.
La mayora de los mtodos JDBC gestionan los errores lanzando
una
excepcin
del
tipo
SQLException.
El
mtodo
getConnection() hace exactamente esto por eso lo metemos
siempre en un bloque try y catch. En general todos los mtodos
definidos por JDBC, al hacer uso de ellos deben de estar dentro de
un bloque try e incluir una sentencia catch para una
SQLException.
Para ver cmo sera una conexin a Oracle, ver el mtodo
obtenerConexionOracle(), de la clase Conexin del paquete
ConexinTest en el aplicativo Sistema_MusicStore_JDBC.

Figura 2.7: Forma de obtener la cadena de conexin o el valor


para el parmetro sourceURL.
Paso 4: Statements y ResultSets (ambas son interfaces)
Este paso es opcional, es decir hasta el paso 2 ya tenemos el
aplicativo haciendo la conexin a la BD como vemos en el
Sistema_MusicStore, en las clases Conexin_1 y Conexin_2.
Statement
La interfaz Statement brinda mtodos para ejecutar sentencias
SQL y obtener los resultados. Como Statement es una interfaz, no
se puede crear un objeto Statement directamente, es decir, no se
puede hacer:
Statementst = new Statement();
Sin embargo, los objetos de las clases que implementan la interfaz
Statement(que se llamaran de aqu en adelante objetos
Statement a lo largo del doc.) se obtienen con una llamada al
mtodo createStatement de un objeto Connection vlido:
Statementstatement = objConexion.createStatement();

Una vez creado un objeto Statement, se puede usar para ejecutar


una consulta SQL llamando a sus mtodos de ejecucin que son
los siguientes:
executeQuery():
Para sentencias SQL que recuperen datos de la BD y retorna
un objeto de tipo ResultSet.
executeUpdate():
Para realizar actualizaciones que no devuelvan un ResultSet.
Por ejemplo:
Sentencias DML: insert, update, delete.
Sentencias DDL: createtable, droptable, alter
table.
El valor que devuelve este mtodo es un int con la cantidad
de filas modificadas.
execute():
Para ejecutar sentencias que devuelven ms de un
ResultSet, ms de un valor de actualizaciones o una
combinacin de los dos. Es decir retorna true si la sentencia
pasada como argumento devuelve un objeto de tipo
ResultSet y devuelve false si la sentencia pasada como
parmetro devuelve una cuenta de actualizacin.
executeBatch():
Los mtodos executeQuery() y executeUpdate()envan
una sola sentencia SQL a la BD. El mtodo executeBatch()
enva un conjunto de sentencias a la BD al mismo tiempo.
Todas las sentencias son ejecutadas y los resultados de cada
sentencia son devueltos como un contador actualizado en
un array al llamante. Como executeBatch() devuelve un
array de contadores actualizados se puede utilizar con
cualquier SQL excepto con las sentencias SELECT.
Podemos ver el concepto de execute() y los mtodos con los
que trabaja en la pg. 99. Sobre executeBacth() podemos
ver conceptos y un ejemplo corto en la pg. 100. Todo esto
en el libro Java 6. Adicionalmente ver ms ejemplos de
aplicacin en el libro Fundamentos de BD con Java.
En nuestro ejemplo, queremos recuperar datos de una base de
datos, as que emplearemos el mtodo executeQuery(). Le
pasaremos un argumento de tipo String con la sentencia SQL.

En conclusin el objeto Statement puede usarse para crear,


recuperar, actualizar y borrar datos de una tabla, procesos que en
su conjunto se conocen con el nombre de CRUD.
ResultSet
El resultado de la consulta se devuelve como un objeto de tipo
ResultSet. Es decir la respuesta de la peticin SQL est contenida
en un objeto que implementa el interfaz ResultSet. Por ejemplo si
tenemos un objeto de tipo Statement llamado st, podramos
escribir:
String comandoSQL = SELECT Apellido, Nombre FROM Artista;
ResulSet rsArtista = st.executeQuery(comandoSQL);

Nota:
Podramos tener declarada una sentencia SQL como por
ejemplo un INSERT y en la parte de VALUES colocar valores
entre comillas simples y comillas dobles.
Comillas simples indican que le estoy ingresando un valor de
cadena de caracteres. En cuanto a las comillas dobles no
forman parte de la sentencia SQL por tanto no se envan a la
BD. (Captulo 9, pag. 316 del libro de BD con Java)
El objeto ResultSet encapsula los datos devueltos por una
consulta, adems contiene un cursor o puntero que puede
manipularse para acceder a cualquier fila del resultado. El mtodo
next() del objeto ResultSet desplazar el cursor a la prxima
posicin. El cursor es vlido hasta que el objeto Statement se
cierre.
Adems los mtodos next() y previous() devuelven el valor
true si el movimiento les lleva a una fila vlida, y false si se
salen de la tabla, condiciones que se pueden controlar en un bucle
while. Se podra procesar todas las filas de un ResultSet con el
siguiente bucle:
While (objResultSet.next())
{
// procesar los datos de la fila
}
El objResultSet empieza con su cursor una fila antes del
comienzo de la tabla. Tambien podemos usar los mtodos
isLast() o isFirst() para comprobar si ha llegado al final o al
comienzo de los resultados.
Acceder a datos en un ResultSet

A travs de un ResultSet podemos acceder al valor de cualquier


columna de la fila actual (indicada por el cursor del ResultSet) por
nombre o por posicin. La interfaz ResultSet declara los
siguientes mtodos bsicos para recuperar datos de columnas a
partir de la fila actual como tipos de datos de Java:
getBoolean()
getDate
getInt()
getBytes()

getFoat()
getTime()
getString()
getDouble()

getShort()
getBigDecimal()

Ver cuadro 2.1 para mayor detalle.


La siguiente tabla ilustra la integracin entre tipos de datos en
SQL y los mtodos apropiados getXXX() del ResultSet.

Cuadro 2.1: El mtodo getXXX() de la izquierda se corresponde


con el tipo de dato de SQL. Los que mejor se integran se indican
con smbolo check y los que tambin podran funcionar se
indican con +/-.

Podemos colocar dos posibles valores entre los parntesis de esos


mtodos getXXX() para recuperar los datos de las columnas:
a. El nombre de la columna en la BD (es igual escribir
Id_Tienda y id_tieNdA).
b. O podemos colocar entre los parntesis un valor entero que
es el ndice de la columna siendo 1 para la primera columna
de la fila actual. Esta ltima forma no es tan recomendable
porque si cambio de orden las columnas o si se cambia el
esquema de tablas de la BD, por tanto cambiar la
numeracin de las columnas y si el 1 apuntaba a la columna
IdTienda,
con
el
cambio
ahora
1
apuntar
a
DireccionTienda por ejemplo.
Trabajar con valores null
En SQL, null significa que no se ha definido un dato para una
columna.
Cuando en la BD existiese un registro null de SQL, el mtodo
getXX() del ResultSet devuelve el valor apropiado para el tipo
devuelto. Ver tabla tabla 2.1:
Mtodo getXXX()
Valor
getByte()
cero
getShort()
cero
getInt()
cero
getLong()
cero
getFloat()
cero
getDouble()
cero
getBigDecimal()
null
getBoolean()
false
getString
null
getDate()
null
getTime()
null
getObject
null
null
si getX retorna un
objeto
Tabla 2.1: Valores en Java que corresponde con el tipo NULL.
La interfaz ResultSet aporta un mtodo para probar un valor de
columna de dentro de un ResultSet, para que de esta forma
determinar si es un null. Este mtodo es wasNull() que devuelve
true o false.
Podemos ver uso de este mtodo en Sistema_MusicStore, la
clase AlbumDAO, en el mtodo BDaResultSet que es usado a
su
vez
por
el
mtodo
ListarAlbunes
y
ListarAlbunesConPortadaVacia.

En resmen:
Las clases e interfaces Connection, Statement y ResultSet son
los componentes de JDBC que usaremos con mayor frecuencia.

Captulo 3: Conectar con una Base de datos


3.1
La clase DriverManager
Como se explic anteriormente, Connection es una interfaz y por
tanto no se puede instanciar llamando a un mtodo constructor.
Obtenemos una conexin llamando al mtodo que devuelve un
objeto Connection. Este mtodo es el getConnection() y
pertenece a la clase DriverManager.
Por tanto, en varias ocasiones si escuchamos decir el objeto
Connection en realidad estamos diciendo instancia de una clase
que implementa la interfaz Connection
En otras palabras la interfaz Connection implementa una clase
llamada DriverManager y esta clase es la que alberga al mtodo
getConnection(), mtodo el cual recin va a devolver un objeto
Connection.

DriverManager
+registerDriver(Driver)
Registrado
+getConnection(String)
+getConnection(String,
Properties)
+getConnection(String,String,St
ring)
cre
+getDriver(String)
+setLoginTimeout(int)
+setLoginTimeout()
+setLogWriter(PrintWriter)
+getLogWriter()
+println()
<<misc>>

Concrete
Connection
Implements
Connection
+close()
+commit()
+createStatement()
+roolback()
+setAutoCommit(boole
an)
<<misc>>

Figura 3.1: En el diagrama UML se muestra la relacin de la clase


DriverManager y la interfaz Connection y los mtodos de cada uno
de ellos.
Como vimos anteriormente, la llamada a Class.forName() hace
que la mquina virtual de Java inicie la clase driver. Este mtodo
toma un parmetro String que es el nombre completo aceptado de
la clase driver especfica. Para una base de datos SQL Server, el
cdigo ser:
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver")

Al decir nombre completo aceptado de la clase driver especfica


estamos diciendo la especificacin del paquete y el nombre de la
clase. Por tanto com.microsoft.sqlserver.jdbc.es el paquete y
SQLServerDriver es la clase.
Nota:
Realmente, existe una segunda forma de iniciar la clase driver
apropiada. Se trata de aadir el nombre de la clase driver a una
lista de posibles drivers que la clase DriverManager inicia. Esta
lista se guarda como una propiedad java.lang.System con el
nombre jdbc.drivers. Cuando la clase DriverManager se inicia,
intentara iniciar cualquier driver JDBC que haya sido identificado
en las propiedades del sistema jdbc.drivers.
Las propiedades del sistema estn realmente almacenadas en un
objeto Properties. La clase Properties, est definida en el
paquete java.util.
Nosotros podemos usar el objeto Properties para suministrar
tanta informacin como necesite nuestro driver. Pero si nuestro
administrador de seguridad hace su trabajo o se ha establecido
una poltica de seguridad, no podremos modificar el objeto
Properties. Por tanto mejor usar en la mayora de casos
Class.forName.
Para mayor detalle revisar el libro Base de Datos con Java,
editorial Wrox y Anaya, pgina 277.

3.2

Conexiones

Existen 3 areas principales que se encuentran bajo el control de


nuestro objeto Connection:
Crear
objetos
Statement,
CallableStatement.
Control de transacciones.

preparedStatement

Obtener objetos DatabaseMetadata.


Para mayor detalle ver aplicativo Sistema_MusicStore y como se
relacionan las clases: Conexin_2, clsTienda y TiendaDAO.

3.3 Problemas: cdigo duplicado para Connection y


sus recursos
A medida que nuestro aplicativo crece y tengamos ms mtodos
como RegistrarTienda en la clase TiendaDAO que requieran
trabajar con conexiones a BD y sus recursos (ResultSet y
Statement) y luego cerrar dichos recursos, podramos incurrir en el
error de colocar ese mismo cdigo de apertura y cierre de recursos
en
todos
los
mtodos
que
vayamos
creando
como
ActualizarTienda,
BuscarTiendaPorID,
BuscarTiendaPorDireccion, etc.
Para evitar eso creamos una clase Conexin_Optima que brinde
una sola conexin al resto de clases que la requieran.
Y para cerrar los recursos (ResultSet, Statement y Connection)
existe una solucin mejor y es la siguiente. Implementar la
siguiente clase:

Ver clase Conexin_Optima para la implementacin.


Ver los nuevos cambios usando esta clase y la forma cmo es que
se le invoca en la clase Conexin_Optima y en TiendaDAO.
Problema al conectar desde un cliente a la BD en un
servidor
Si estamos ya listos para desplegar nuestra aplicacin en un
entorno real, colocamos nuestra BD en un Windows Server 2008
por ejemplo y si intento conectarme desde un cliente o acceder a la
BD del servidor y tengo problemas, una de las causas podra ser un
problema con los puertos. Para solucionar esta posible situacin,
estando en el SO del cliente, agregar una excepcin en el firewall
habilitando el puerto 1436 para SQL Server o el puerto 3306 para
MySQL.

Captulo 4: Trabajando con datos relacionales


en nuestra aplicacin. Usando ResultSet y
RowSet.
Digamos que estas 2 interfaces es como trabajar clases de la
capa conectada y desconectada de ADO.NET.
Un ResultSet siempre requiere de un objeto Connection
abierto y un RowSet no necesariamente.
Con un RowSet se puede recuperar el dato y verlos estando
desconectados de la BD. Podemos hacer modificaciones a los
datos y volver a conectar cuando estemos listos para aplicar
todos los cambios. A continuacin veremos ms detalles de
ambas interfaces.

4.1

Ventajas del ResultSet

En un aplicativo sencillo que permita ver los resultados de una


consulta a una BD en un componente grafico Jtable, este
presentara directamente los datos contenidos en una consulta
ResulSet. Se puede hacer modificaciones en los datos de la
tabla y enviar inmediatamente a la BD.
El ResultSet trabaja con una conexin abierta, por tanto no
tiene necesidad de crear objetos dato en memoria, es decir nos
evita de iniciar muchos objetos dato en la memoria ya que los
tiene a la mano por estar trabajando en una conexin abierta.
Si de momento necesitamos 25 columnas de una vez, se solicita
tal cantidad y en caso que luego se requiera a partir de la fila
26, simplemente se hace la solicitud.

4.2

Desventajas del ResultSet

Cuando desarrollamos a gran escala por ejemplo para 500 usuarios,


no realiza el uso ms eficaz de determinados recursos. Para

contrarestar esto hacemos uso de restricciones en la interfaz


Statement como por ejemplo restricciones de mximo nmero de
filas y desconexin por tiempo de consulta. Lo veremos ms
adelante.
Los objetos ResultSet tienen lugar en una conexin activa con la
BD y no se pueden serializar en un cliente remoto como es un
applet o un dispositivo sin cables. Para acceder a los datos, el
ResultSet, la consulta y la conexin a la BD, han de crearse en la
aplicacin remota.
En el ejemplo del Jtable y la vista de datos, el usuario mantiene una
conexin abierta todo el tiempo que est trabajando el ResultSet.
Esto podra ser una desventaja tanto como ventaja (como se vio en
3.1) ya que si todas las conexiones disponibles para esa BD se
estn usando de acuerdo al mximo de licencias permitidas, otro
cliente tendra que esperar n minutos para que alguna conexin
quede libre.
En conclusin este mtodo a gran escala es uno de los primeros en
fallar.

Utilizar un RowSet

Como se vio anteriormente el tener una conexin abierta es


muchas veces una desventaja. JDBC 2.0 mejora estos problemas
con la extensin de la interfazResultSet: la interfaz RowSet. Para
mayor detalle ver captulo 11 del libro Bases de Datos con Java.

4.3

Ventajas del RowSet

RowSet encapsula informacin necesaria para conectar con una


BD.
Las implementaciones de RowSet son serializables despus que
nos desconectemos de la BD.
Encapsulando la informacin necesaria para conectar a la base de
datos, puede existir un RowSet fuera del contexto de un objeto
Connection. Esto con el fin de tener conexiones libres para
cualquier otra consulta de otro usuario.

4.4

Desventajas del RowSet

Debido a su naturaleza desconectada, es totalmente posible


para un usuario, recuperar remotamente un RowSet, realizar
cambios y cuando vengan a actualizarse a la BD encontrar que
alguien ha actualizado ya la informacin antes de volver a
conectar el RowSet original.
El resultado devuelto puede acaparar la memoria del sistema si
es muy grande cuando el RowSet est desconectado.

Dado que un RowSet se puede ver totalmente cuando est


desconectado, todos los datos se inician en memoria.

4.5 Transformar el ResultSet en una representacin


XML
Actualmente la industria del software se est moviendo hacia la
independencia de los datos tanto de plataforma como de lenguaje y
tratan de encontrar un modo neutral de representar los datos. La
introduccin y la adopcin de XML ha sido un gran paso a estas
necesidades. XML estandariza la representacin de datos
independiente de plataforma.
Un ejemplo de aplicacin para esto es el uso de Web Service que
como se vi en el ejemplo del curso de Proyectos II, un Web Service
implementado en .NET ofrece datos y un aplicativo en otro lenguaje
como en java los consume. Todo esto es porque el web service
entrega datos en XML paraqu el aplicativo en Java los pueda leer.

4.6

Integrar datos relacionales en objetos Java

En muchas ocasiones existe una relacin muy sencilla entre las


columnas de una tabla y los atributos de un objeto. En este caso la
tarea de integracin consiste simplemente en hacer coincidir los
tipos de datos de la base de datos con aquellos de Java.
Ejemplo: Observar el mtodo BDToResultSet

CAPITULO 5: Sentencias Preparadas


Hasta el momento, se obtiene el objeto Statement y se usa para
consultar, registrar, actualizar y eliminar datos a travs de comandos
SQL. Como ya sabemos este proceso requiere que el driver enve la
sentencia SQL completa a la BD para ejecutar. Luego la BD compila,
ejecuta la sentencia SQL y devuelve el resultado al llamante. Todo este
proceso es independiente de si la sentencia SQL se ha pasado antes. Sin
embargo con frecuencia enviamos a la BD las mismas columnas en las
mismas tablas y solo variarn los valores.
La interfaz PrepareStatement
Esta interfaz aporta un significado a la creacin de sentencias
reutilizables que pueden ser precompiladas por la BD.
Cuando deseamos insertar valores en la tabla Tienda, hacemos lo
siguiente:
INSERT INTO Tienda
(Descripcion,Id_TipoTienda,Direccion,Ciudad)
VALUES
('Tienda sucursal',2,'Florencia','Trujillo')

Cuando se necesita una nueva entrada en la tabla Tienda, ejecutamos


otra cadena de caracteres SQL:
INSERT INTO Tienda
(Descripcion,Id_TipoTienda,Direccion,Ciudad)
VALUES
('Tienda principal',2,'El Golf','Trujillo')

Como vemos ambas sentencias SQL son las mismas y ambas insertan
datos en las mismas columnas en la misma tabla. Lo que cambia tan
solo es el valor del dato que se inserta (vemos que el valor para las
columnas Id_TipoTienda y Ciudad no cambian). Sin embargo, cada vez
que un nuevo dato es insertado, el cdigo enviar la sentencia SQL
completa a la BD en donde esta sentencia es procesada y ejecutada. Si

queremos insertar otra fila, vuelve a enviarse y vuelve a ser procesada


y ejecutada la misma sentencia SQL.
El tiempo de procesamiento consiste en pasar la sentencia SQL,
comprobar la sintaxis y la semntica y generar el cdigo. A Menudo este
tiempo de procesamiento es mayor que el tiempo necesario para
ejecutar la sentencia. Lo ms adecuado sera mejorar el rendimiento
dicindole a la BD: Aqu hay sentencias SQL que necesitan ser
ejecutadas varias veces con distintos valores de datos. Deja listo para
ejecutarse esta sentencia SQL y solo te enviar los datos. La base de
datos procesar la cadena de caracteres una vez aunque la sentencia se
ejecute varias veces.
La interfaz PreparedStatement hace justamente eso, es decir se usa
para pasarle una cadena de caracteres SQL a una BD. Adems esta
interfaz nos brinda mtodos para asignar datos para asignar en la BD,
una vez que le hemos dicho que ejecute la sentencia SQL.

Figura 5.1: La interfaz PreparedStatement extiende a la interfaz


Statement.
Hereda todos sus mtodos y aade otros.
Entonces, ahora modificaremos las sentencias insert de hace un
momento de tal forma que usen sentencias preparadas.
INSERT INTO Tienda
(Descripcion, Id_TipoTienda, Direccion, Ciudad)
VALUES

(?, ?, ?, ?)
// 1 2 3 4
Los signos de pregunta se les denominan placeholder que representan
los datos que sern asignados ms tarde (variables en la BD). Los
nmeros que estn debajo son los ndices de cada placeholder
Las sentencias preparadas son el mtodo preferido de ejecucin de
consultas SQL cuando usan valores que introducen los usuarios.
El cdigo necesario para crear una PreparedStatement con las
sentencias SQL insert anteriormente descritas quedara de la siguiente
manera:
String comandoSQL = "INSERT INTO Tienda"
+ "(Descripcion, Id_TipoTienda,Direccion,Ciudad)"
+ "VALUES"
+ "(?, ?, ?, ?)";
PreparedStatement pst = objConexion.prepareStatement(comandoSQL);

Luego de crear la sentencia preparada pero antes de que se ejecute, los


placeholder deben ser asignados en la sentencia. La interfaz
PreparedStatement define varios mtodos para hacer eso y son los que
veremos en la figura 5.2:

Figura 5.2: Mtodos para los tipos nativos de Java.


El primer argumento en cada mtodo de la tabla es el ndice del
parmetro en la cadena de caracteres SQL, es decir cada placeholder se
corresponde con el primer argumento.
El segundo argumento es el valor del dato que reemplaza al
placeholder.

Finalmente, el uso de PreparedStatement con la sentencia SQL y sus


placeholder mostrar algo similar a esto:
String comandoSQL = "INSERT INTO Tienda"
+ "(Descripcion, Id_TipoTienda, Direccion, Ciudad)"
+ "VALUES"
+ "(?, ?, ?, ?, ?, ?)";
// 1 2 3 4 5 6
PreparedStatement pst = objConexion.prepareStatement(comandoSQL);
pst.setString(1, "Tienda principal");
pst.setInt(2, 2);
pst.setString(4, "Arequipa");

Notas:
Tener en cuenta que tambin puedo usar PreparedStatement si
necesito usar select * From
Los valores de los datos se pueden asignar en cualquier orden,
siempre que obtengamos el ndice correcto.
Estamos obligados a asignar todos los parmetros antes de
ejecutar el cdigo SQL, de lo contrario se lanzar una
SQLException.
Si deseamos asignar un valor null para algn placeholder, haremos
uso de uno de los mtodos setNull() que aparece en la figura 5.2.
En algunas ocasiones y para algunos motores de BD, es necesario
establecer el parmetro useServerPrepStmts = true. Esto sera de
la siguiente manera:
Connection conexion = DriverManager.getConnection
("jdbc:mysql://servidor/basedatos?useServerPrepStmts=true",
"usuario", "password");
Una vez que asignamos un valor para un placeholder, ese valor
permanece asignado para ese placeholder hasta que el cdigo cambie
ese valor explcitamente. Por tanto mientras usemos la misma sentencia
preparada, no tenemos que estar asignando valor al mismo placeholder
cada vez que queramos ejecutar la misma sentencia SQL. Solo se asigna
valor al placeholder la primera vez.
Para cambiar el valor del placeholder, hacemos una llamada a uno de
los mtodos setXXX() otra vez con el ndice apropiado:
pst.setString(4,"Chiclayo");
pst.executeUpdate();
// En algn sitio ms alejado del cdigo:
pst.executeUpdate(); // Parmetro 6 ya fue asignado y es Chiclayo.
//En algn sitio ms alejado del cdigo, necesitamos insertar
//otra ciudad:
pst.setString(4,"Puno");

// Si queremos limpiar todos los valores de los parmetros:


pst.clearParameters();

Como vemos para ejecutar la sentencia SQL hacemos uso del mtodo
executeUpdate(). Es decir, podemos hacer uso de los mismos
mtodos que al ejecutar un Statement as como podemos usar
tambin executeQuery() y execute(). Pero en este caso ya no se
toma como argumento la query ya que no necesita ser enviada con uno
de esos 3 mtodos ya que ya fue enviada a la BD con la llamada al
mtodo prepareStatement(). Si hacemos lo contrario a esto se
lanzar una SQLException.
En resmen:
Cuando hay que ejecutar varias veces la misma instruccin SQL con
valores diferentes, las instrucciones preparadas suelen ejecutarse
mucho ms rpido dado que estn precompiladas. Por tanto Las
sentencias preparadas aportan mejor eficacia de nuestra aplicacin
JDBC.
Ejemplo de uso:
PreparedStatement pstmt = objCon.preparedStatement(comandoSQL);

pstmt.setString(1,"C-9732");
pstmt.setString(2,"Navacerrada");
pstmt.setInt(3,1200);
pstmt.executeUpdate();
pstmt.setString(1,"C-9733");
pstmt.executeUpdate();

CAPITULO 6: Sentencias de llamada y


Procedimientos almacenados
6.1

Procedimientos almacenados

Son procedimientos que estn almacenados en la BD.


Los
procedimientos
almacenados
(PA)
pueden
tomar
parmetros de entrada como argumento o pueden no tomar
ningn parmetro.
Pueden devolver un valor al llamante o pueden no devolver
nada.
Los PA proporcionan encapsulacin y reutilizacin de
funcionalidades, control de transacciones y la estandarizacin
de las reglas del negocio.
En este captulo, el termino procedimiento almacenado se usa
para referirse tanto a procedimientos como a funciones. La
principal diferencia entre los dos es que una funcin devuelve
un valor y un procedimiento no devuelve ningn valor.
Tipos de parmetros
Los procedimientos pueden usar parmetros los cuales pueden ser
de tipo de SQL y tendrn uno de estos 3 modos: IN, OUT, INOUT.
a. Parmetros IN: parmetros usados para pasarle un valor a
un PA para que pueda utilizarlo. Los PA usan pero no cambian
el valor del parmetro IN.
b. Parmetros OUT: tipo de parmetro que es devuelto por el
procedimiento. Es decir, en el curso de la ejecucin del
procedimiento, este asignara un nuevo valor al parmetro OUT.
c. Parmetros INOUT: son parmetros que se usan para
pasarle informacin a un PA, que a su vez les asigna un nuevo
valor. Es decir el procedimiento usa el valor que le pasa el
parmetro como si se tratase de un parmetro IN, y puede
asignarle un nuevo valor a este parmetro como si se tratase
de un parmetro OUT.
Los parmetros IN pueden ser utilizados por procedimientos
como por funciones. Los parmetros OUT e INOUT se usan

normalmente con procedimientos. Esto se trata de buenas


prcticas ms no de un requisito.
Adems una funcin almacenada ya devuelve un valor, aunque
uno puede programar que una funcin devuelva mltiples
valores usando parmetros OUT e INOUT, no es el mejor estilo de
programacin. Podra haber ocasiones en las que haya sentido
hacer que una funcin devuelva mltiples valores, generalmente
es un sntoma que la funcin almacenada est tratando de hacer
demasiado y debera de ser refactorizada en dos o ms funciones
o procedimientos.
6.2 Sentencias de llamada
La interfaz CallableStatement permite que un cdigo Java haga
llamadas a los procedimientos almacenados. La interfaz
CallableStatement
extiende
la
interfaz
PreparedStatement
proporcionando mtodos para ayudar a llamar a procedimientos
almacenados.
Crear una sentencia de llamada
Un objeto CallableStatement se crea prcticamente del mismo
modo que un objeto PreparedStatement, llamando a un mtodo del
objeto Connection.
Observemos la siguiente tabla que recoge una lista de todos los
mtodos de la interfaz Connection que sirven para crear un objeto
CallableStatement:
Mtodo
PrepareCall(String sql)

PrepareCall (
String sql,
int resultSetType,
int resultSetConcurrency )

PrepareCall (
String sql,
int resultSetType,

Descripcin
Crea
un
objeto
CallableStatement para el sql
dado. Si el CallableStatement
devuelve un objeto ResultSet,
el ResultSet tiene un tipo
forward
only,
no
es
actualizable y no es holdable.
Crea
un
objeto
CallableStatement para el sql
dado. Si el CallableStatement
devuelve un ResultSet, el
ResultSet
tiene
el
tipo
ResultSet dado y concurrencia
y no es holdable.
Crea
un
objeto
CallableStatement para el sql

int resultSetConcurrency,
int resultSetHoldability )

dado. Si el CallableStatement
devuelve un ResultSet, el
ResultSet
tiene
el
tipo
ResultSet dado, concurrencia y
holdability.

El tipo se refiere al modo en el que uno puede atravesar un


ResultSet. La actualizabilidad se refiere a la capacidad de cambiar
una base de datos mediante ResultSet. La holdability se refiere a si
un ResultSet se cierra cuando se llama al mtodo commit().
El primer argumento de cada mtodo prepareCall() es una cadena
de caracteres conformada por la palabra call seguido del nombre
del PA.

La forma ms bsica del sql es el que no toma parmetros:


String sql = { call SP_InsertarCliente};
CallableStatement cs = connection.prepareCall (sql);
Cuando un procedimiento o funcin toma parmetros, es de la
siguiente forma:
String sql = { call SP_InsertarCliente(?,?)};
CallableStatement cs = connection.prepareCall (sql);
Ver ejemplo en Sistema_MusicStore clase ArtistaDAO.
Finalmente, el sql para llamar una funcin almacenada es el
siguiente:
String sql = ?= { call SP_InsertarCliente(?)};
CallableStatement cs = connection.prepareCall (sql);
Uso de placeholders
Los smbolos ? dentro de los parntesis corresponden a los
placeholders como se dijo en captulos anteriores.
Tras preparar la sentencia de llamada pero antes de que la
sentencia pueda ser ejecutada, los valores de los placeholders para
cualquier parmetro IN e INOUT en la sentencia deben de ser
asignados, caso contrario se lanzar error.
Para llevar esto a cabo, la interfaz CallableStatement hereda los
mtodos setXXX(). Algunos son los siguientes:
void setDouble(int indice, double x)
void setInt (int ndice, int x)
void setString(int indice, String x)

El primer argumento es el ndice del parmetro en la cadena de


caracteres SQL y el segundo parmetro es el valor que reemplazar
al placeholder.
Si alguno de estos parmetros son de tipo OUT, deben de ser
registrados antes que se ejecute la llamada. Esto se lleva a cabo
con los siguientes mtodos:
void
registerOutParameter
jdbcType)
void
registerOutParameter
jdbcType, int scale)

(int

parameterIndex,

int

(int

parameterIndex,

int

El primer argumento en el mtodo es la posicin del placeholder en


la cadena SQL. El segundo parmetro es una de las constantes
definidas en la clase java.sql.Types. La clase Type tiene una
constante para cada tipo genrico de SQL.
Aqu tenemos una lista parcial de las constantes definidas en la
clase Type:
int SMALLINT
int INTEGER
int FLOAT
int DOUBLE
int NUMERIC
int DECIMAL
int CHAR
int VARCHAR
int DATE
Vemos que cada constante es un int el cual es el tipo de dato que
se requiere para el segundo parmetro en el mtodo
registerOutParameter(), ejemplo:
cs.registerOutParameter(2, java.sql.Types.STRING)
Nota:
1. Cuando se registra un tipo parmetro OUT que es de uno de los
tipos numricos como FLOAT, DOUBLE, NUMERIC o DECIMAL se
puede
usar
la
segunda
forma
del
mtodo
registerOutParameter() ya que en su tercer parmetro se
define la escala del parmetro OUT. Por ejemplo si el PA retorna
el precio de algn producto, normalmente tienen la escala de 2
(2 dgitos a la derecha de la coma), por tanto el mtodo quedara
de la siguiente manera:
cs.registerOutParameter(1, java.sql, Types.DOUBLE,2);

2. Si alguno de los placeholders representa un parmetro INOUT, el


cdigo
debe
llamar
a
los
mtodos
setXXX()
y
registerOutParameter() antes de ejecutar la llamada al PA. Caso
contrario se lanza una SQLException.
Luego de ejecutar los CallableStatement, para obtener los valores
de los parmetros OUT e INOUT debe de usarse los mtodos
getXXX() parecido a la forma de recuperar valores de un resultset.
Ver ejemplo en Sistema_MusicStore, clase ArtistaDAO, mtodo
editarArtista().
Actualizaciones en bloque

6.3

CAPITULO 7: Data Sources (revisar luego de


haberlo estudiado bastante)
Mientras que la utilizacin de JDBC a travs de los URL estndar e
internet proporciona un medio estndar para identificar una conexin a
base de datos, existe adicionalmente otra caracterstica, el DataSource
o fuente de datos.
La interfaz DataSource introducido en el paquete adicional javax.sql,
proporciona una arquitectura ms flexible para crear y usar conexiones
con bases de datos dado que podremos acceder a diferentes BDs sin
hacer un solo cambio en el cliente (aplicacin). Oculta los detalles de la
conexin para que el programador no tenga que preocuparse del URL,
servidor, puerto, etc.
Adems, el DataSource permite:
Encapsular informacin necesaria para establecer una conexin a
base de datos, dando lugar a una cdigo ms potable y ms fcil
de mantener que si se usara un URL.
Simplifica la implantacin y constituyen el fundamento para otras
caractersticas avanzadas como el pool de conexiones y las
transacciones distribuidas.
Pool de Conexiones:
Cada vez que un recurso se conecta con una BD, crea una
conexin fsica de bases de datos. En JDBC esto se convierte

7.1

en un objeto Connection, que tienen un costo (crear la


conexin, mantenerla y liberarla cuando ya no es necesaria).
El uso de un pool de conexiones para reservar y devolver
objetos de conexin permite minimizar este costo ya que no
crea ni destruye conexiones constantemente, sino las reutiliza.
Transacciones distribuidas:
Adems de gestionar transacciones que impliquen una nica
conexin a una base de datos, ahora tambin es posible
gestionar transacciones que abarquen varios orgenes de
datos o mltiples conexiones.

Conceptos y terminologa del DataSource


Aplicacin

API JDBC
Gestor de drivers JDBC Objeto DataSource
Driver JDBC

Servidor de Base de Datos

Figura 7.1: Arquitectura JDBC.


El diagrama muestra que una aplicacin acceder a un servidor d
base de datos mediante un conjunto de capas de software, siendo

la primera de ellas JDBC. Este API conlleva al uso de un


determinado tipo de driver.
El diagrama muestra que el DataSource asume la responsabilidad
de la conexin entre la aplicacin y el driver JDBC, un papel que
normalmente le correspondera al DriverManager (que todava
puede asumirlo) al usar los URL de JDBC para una conexin.

7.2

DataSources

Hasta el momento se ha venido trabajando con una clase llamada


Conexion
en
la
que
se
implementa
los
mtodos
obtenerConexion() y cerrarConexion() para interactuar con la
BD. El problema es que esta clase sigue perteneciendo al cdigo de
la aplicacin y si queremos cambiar los parmetros de
configuracin de acceso a la BD, tendramos que hacerlo en dicha
clase y finalmente tendramos que recompilar nuestra aplicacin.
Aqu aparece el DataSource. Estas son sus principales
caractersticas tcnicas:
Se crea y se gestiona al margen de nuestra aplicacin.
Podemos modificar el DataSource para acceder a bases de
datos distintas sin hacer un solo cambio en nuestra aplicacin.
Oculta los detalles de la conexin de modo que el
desarrollador nunca se preocupe por la URL de la conexin, el
puerto, servidor, etc.
Posibilita la utilizacin de caractersticas a nivel de empresa
como es el uso de pool de conexiones y transacciones
distribuidas.
El DataSource es una interfaz de modo que al igual que las
otras interfaces como Connection, ResultSet, etc, nuestro
cdigo cliente usar variables de tipo interfaz. Por ejemplo,
cuando obtenemos la conexin con DriverManager, la variable
es de tipo Connection:
Connection con = DriverManager.getConnection(. . .)
La variable con es de tipo de la interfaz Connection pero a su
vez con almacena el objeto devuelto por DriverManager,
objeto el cual fue instanciado a partir de una clase
proporcionada por el fabricante del driver.
Si trabajamos con SQL Server, esta clase es SQLServerDriver
y est en la ruta: com.microsoft.sqlserver.jdbc.
Al crear una fuente de datos para una base de datos SQL Server, el
cdigo que crea la fuente de datos del lado del servidor necesitar
las siguientes importaciones:
import java.sql.*;

import javax.sql.*;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource
La ltima importacin la brinda el fabricante del driver y es
necesaria para crear una instancia especfica de DataSource.
Del lado del cliente, este solo necesita los paquetes java.sql y
javax.sql. Cuando el cliente busca el DataSource, la variable que
referencia a ese objeto es una variable tipo DataSource aunque el
objeto real sea una clase especfica cmo SQLServerDataSource.
Es algo similar al uso de:
List<Cliente> listaDeClientes;
listaDeClientes = new ArrayList<Cliente>();
En el ejemplo, la variable listaDeClientes hace referencia a un
objeto de tipo List aunque el objeto real sea una clase especifica
como ArrayList.

Tipos de DataSource
Existen 3 formas de implementar un DataSource:
a. Implementacin bsica:
Produce un objeto DataSource bsico, estndar, que
implementar la interfaz javax.sql.DataSource.
Una implementacin bsica de DataSource produce objetos
Connection que no se usan en un pool ni en una transaccin
distribuida.
Esta es la forma ms costosa en trminos de procesamiento, ya
que los objetos Connection deben establecerse desde cero cada
vez y se utilizan en entornos de una sola capa en los que la
aplicacin y la base de datos no estn separados.
b. Implementacin de pool de conexin (Connection pooling
implementation):
Produce un objeto Connection que participar automticamente
en un pool de conexin.
Adems, una clase DataSource con soporte a pool de
conexiones permite reutilizar los objetos Connection, ofreciendo
por tanto un mejor rendimiento. Este tipo de DataSource
implementar la interfaz javax.sql.ConnectionPoolDataSource

que ser el fabricante del driver que brindar la clase que


implemente esta interfaz.
Una vez instanciado un objeto ConnectionPooledDataSource, las
llamadas a su mtodo getPooledConnection(), devolvern un
objeto PooledConnection: una conexin fsica que puede
almacenarse en la memoria cach.
Del lado del cliente, el programador usar variables de tipo
DataSource. Cuando estas llamen a getConnection(), no sabrn
si el objeto subyacente es un DataSource o un
ConnectionPoolDataSource. Ver ms detalles ms adelante.
c. Implementacin de transaccin distribuida
Una clase DataSource que soporta transacciones distribuidas
produce objetos Connection que pueden participar en una
transaccin distribuida; esto es, una transaccin en la que
interviene ms de un servidor DBMS. Este tipo de DataSource
implementar la interfaz javax.sql.XADataSource y devolver un
objeto Connection de tipo XAConnection.

Cmo funciona un DataSource?


Como se dijo, un DataSource es la informacin necesaria para
establecer una conexin a base de datos, encapsulada en un objeto
Java que se almacena a continuacin en un servicio de directorio.
El cliente establece entonces una conexin fsica a base de datos a
travs de este DataSource nombrado:

Servicio de nombres y directorios


Cliente
DataSource
DataSource

Figura 7.2

El cliente puede ser un EJB, un servlet o una aplicacin Java. En


cualquiera de los casos, el DataSource puede buscarse usando JNDI
como ocurre con cualquier otro objeto Java almacenado en un
Servicio de Directorios. El mtodo getConnection() puede aplicarse
entonces al objeto DataSource para establecer una conexin a base
de datos. La interfaz JNDI se ocupa de la bsqueda; el objeto
DataSource se ocupa de la conexin a base de datos.
En otras palabras, el JNDI:
Es un API que facilita el acceso a los diferentes tipos de
servicios de nombres y directorios.
Un servicio de nombres es un almacn de informacin al cual se
puede acceder a travs de la red. Esto permite eliminar
dependencias en la aplicacin respecto de un driver o URL en
concreto.
Busca un DataSource en un Servicio de nombres y directorio.
Los detalles de comunicacin con un directorio en particular son
aportados por bibliotecas especficas de directorio, de modo
simular como ocurre con los drivers JDBC.

Utilizacin del DataSource


Hay dos formas de crear el DataSource:
a. Programndolo mediante java y varios APIs. Aqu se crea y se
registra el DataSource manualmente.
b. Usando alguna herramienta que suelen suministrar con los
servidores de aplicaciones. Esta tcnica crear y registrar
automticamente el DataSource.
Para que un cdigo cliente pueda obtener una conexin de un
DataSource, debe crearse primero un objeto DataSource y debe
unirse a un directorio. Ver detalles en el paquete datasource en el
aplicativo Sistema_MusicStore_JDBC

7.3

APENDICE 1: Trabajando con conexin a base de


datos en NetBeans y SQL Server.
Cuando necesitemos trabajar con conexin a base de datos en
NetBeans, debemos de seguir los siguientes pasos:
a. Crear la base de datos e implementar con sus respectivas tablas,
procedimientos almacenados, etc.
b. Por motivos de seguridad en vez de trabajar con el usuario sa,
debemos de crear un nuevo inicio de sesin, en este caso escog
Hanso y asignar la BD sobre la cual ser propietario (check en
db_owner).
c. Verificar desde el NetBeans que ste pueda conectarse a dicha BD
recin creada. Lo podemos hacer siguiendo la figura 1.1, 1.2 y 1.3.
d. Crear la clase conexin que contendr toda la lgica de acceso a la
base de datos. Esta clase se recomienda crearla dentro de una
capa DAOs si es que estamos trabajando bajo un modelo en Ncapas.

Figura Apndice 1.1

Figura Apndice 1.2

Figura Apndice 1.3: Hanso es el usuario que se cre en SQL


Server por motivos de seguridad (Para ya no tener que usar a sa).

APENDICE 2: Gestin de errores


En la mayora de ejemplos vistos nos limitamos a mostrar simplemente
la excepcin que se generar cuando se produce un error:
try
{
// realizar operaciones JDBC.
}
catch (SQLException sqle)
{
System.err.println(sqle);
}

De esa forma se invoca al mtodo toString() para el objeto Exception y


muestra un resultado. El uso de SQLException es bastante genrico de
tratar errores JDBC y se puede mejorar.
Para poder hacer cosas tiles con SQLException, es necesario saber que
hay 3 datos imporatnes en un objeto tipo excepcin. El uso que se le
den a estos datos depende de las posibilidades que ofrezca cada
aplicacin.
1. El mensaje
2. El estado SQL:
Dato sobre la excepcin que ha tenido lugar. Es una cadena que
contiene un estado definido por el estndar X/OpenSQL y que se
obtiene mediante una llamada al mtodo SQLState().
El estndar X/OpenSQL dicta que el estado SQL es una cadena de
cinco caracteres formada por dos elementos. Ms informacin en la
pgina 88 del libro Fundamentos de Base de Datos con Java.
3. Valor del fabricante
El tercer dato que se puede obtener de una excepcin es el Vector
Error Code (o cdigo de error del fabricante).

PENDIENTES
Diseo de BD:
Revisar reglas normalizacin. Ver pag 176.
Repasar temas importantes de la pag. 324 a 330 y documentar
si fuera necesario.
Dejar indicado y con corta referencia acerca de los movimientos
a travs de un resultset de la pag. 330 a 336. Documentar.
Revisar de pag. 437 y hacer ejemplo de 439. Revisar explicacin
de 440 a 442. (SP con metadatos.)
Ver ms ejemplos de aplicacin con batch().
Libro Java 6:
Falta revisar el uso de factory segn la pg. 109, 110, 111, 112.

S-ar putea să vă placă și