Está en la página 1de 0

LECCIN 7

BASES DE DATOS


7.1 BASES DE DATOS RELACIONALES
La mayor parte de las bases de datos que se utilizan son relacionales, por
tanto los conceptos y ejemplos que se desarrollan en este captulo se refieren en su
totalidad a este tipo de bases de datos. Una base de datos relacional puede contener
un conjunto de tablas relacionadas entre s; cada tabla est definida por una serie de
campos y conformada por una lista de tuplas. En el grfico siguiente se muestra un
ejemplo explicativo de estos conceptos.
Los campos forman las columnas de las tablas; definen el tipo y variedad de
sus datos. Las filas de datos se denominan tuplas o registros; una tabla puede estar
vaca (sin ninguna tupla) o contener un nmero variable de las mismas. En el
ejemplo, cada tupla de la tabla Clientes define ciertos datos bsicos de una persona
(cliente), mientras que cada tupla de la tabla Productos define los datos necesarios
de cada producto disponible. Por supuesto, cada tabla de una base de datos puede
contener un nmero de tuplas diferente al de las dems tablas.
A cada valor de un campo definido en una tupla, se le denomina atributo. En
el grfico, todos los textos y valores numricos representan atributos de las tablas.
Las tablas pertenecientes a una base de datos relacional pueden
relacionarse entre s utilizando campos clave comunes entre las tablas. En el
ejemplo, el campo DNI de la tabla Clientes y el campo DNI de la tabla Pedidos
permiten determinar el Nombre, Apellido y Edad de las personas que han realizado
pedidos. As mismo, los campos Producto de las tablas Productos y Pedidos,
permiten conocer el Nombre y Valor de los productos de los que se ha realizado
algn pedido. Relacionando las tres tablas del ejemplo, podemos determinar las
cantidades de cada producto que hay que proporcionar a cada cliente (indicando su
nombre y apellidos), as como conocer la cantidad de dinero que se le debe cobrar.

122 JESS BOBADILLA SANCHO














Adems de los datos (explcitos) de una base de datos (los atributos), existe
una informacin importante: los metadatos. Los metadatos se encuentran
recopilados en un conjunto de tablas del sistema, denominado catlogo. Los
catlogos almacenan informacin acerca de las bases de datos, las tablas y la
composicin de dichas tablas, es decir, de toda la informacin presentada en el
grfico anterior, exceptuando los atributos.
A lo largo de este captulo se mostrar la manera de consultar, modificar,
insertar y borrar datos en las tablas de una base de datos relacional. Parte de estas
manipulaciones se realizar utilizando mtodos de Java, aunque existe un lenguaje
estndar de acceso a bases de datos relacionales que nos simplifica mucho esta tarea,
especialmente cuando manejamos varias tablas de manera simultnea. Este lenguaje
se denomina SQL (Structured Query Language).

DNI Nombre Apellido Edad
5084 Luis Rodrgue 47
5790 Elena Martn 14
1413 Jorge
Sojo
24
DNI Producto Unidades
5084 A07 12
5790 R03 1
1413 A14 6
Producto Nombre Valor
A01 Patatas 3.10
A02
Tomates
1.75
R015 Camiseta 8.40
Clientes
Productos
Pedidos
Tienda
Campos
Atributos
Tabla
Base de datos
Tuplas
JESS BOBADILLA SANCHO 123

7.2 STRUCTURED QUERY LANGUAGE (SQL)
SQL es un lenguaje de manipulacin de bases de datos relacionales
ampliamente utilizado en el desarrollo de aplicaciones informticas. Resulta muy
legible y potente, por lo que es recomendable usarlo lo mximo posible cuando se
desarrollan aplicaciones en Java que emplean bases de datos.
En este apartado se describir muy brevemente alguna de las posibilidades
del lenguaje SQL, que se emplear en diversos ejemplos de este mismo captulo. Las
sentencias de SQL se dividen en dos grupos: Data Definition Language (DDL) y
Data Manipulation Language (DML). Nosotros prestaremos especial atencin al
segundo grupo.
La sentencia CREATE pertenece al tipo DDL y nos permite crear tablas en
una base de datos. En general podremos crear las bases de datos y sus tablas de
manera esttica, utilizando el entorno de gestin correspondiente (Oracle, SQL,
Access, etc.), aunque en otras ocasiones resulta necesario crearlas de manera
dinmica, por ejemplo en un foro, cuando se desea incluir un nuevo tema de
discusin.
La sentencia CREATE que genera la tabla Clientes presenta el siguiente
aspecto:

CREATE TABLE Clientes (
DNI CHAR(10) NOT NULL PRIMARY KEY,
Nombre CHAR (10) NOT NULL,
Apellido CHAR(25) NOT NULL,
Edad INT NOT NULL,
);
Se ha definido el campo DNI como clave primaria, lo que provoca la
creacin de un ndice y nos asegura que no podrn existir dos atributos iguales (dos
DNIs iguales) en dicho campo. Por ser NOT NULL, no se permite la insercin de
un atributo vaco. El resto de los campos, de tipo alfanumrico y entero, tambin ha
sido definido como NOT NULL.
Una vez definidas (esttica o dinmicamente) las tablas de una base de
datos, estamos en condiciones de insertar, borrar, modificar y seleccionar los
atributos que irn conformando el contenido de cada tabla.

124 JESS BOBADILLA SANCHO
7.2.1 Trabajando con una sola tabla
Para aadir una tupla en la tabla Clientes, utilizamos la sentencia INSERT:
INSERT INTO Clientes (DNI, Nombre, Apellido, Edad) VALUES (5084, Luis,
Rodrguez, 47)
Puesto que estamos aadiendo todos los campos, podemos prescindir de su
enumeracin:
INSERT INTO Clientes VALUES (5084, Luis, Rodrguez, 47)
En general, tenemos la posibilidad de incluir nicamente un subconjunto de
atributos de la tupla, aunque en este caso no nos est permitido dejar campos sin
definir, es decir con valor NULL.
INSERT INTO Clientes (DNI, Apellido) VALUES (5084, Rodrguez)
La sentencia SQL que vamos a utilizar de manera ms habitual es la de
seleccin (SELECT). En la siguiente sentencia se seleccionan todos los atributos
correspondientes a los campos Nombre y Apellido en todas las tuplas de la tabla
Clientes.
SELECT Nombre, Apellido FROM Clientes
Anlogamente, para seleccionar nicamente las edades:
SELECT Edad FROM Clientes
Si deseamos seleccionar todos los campos, podemos incluir de manera
explcita cada uno de ellos, o bien hacer uso del carcter * , que significa: todos
los campos de la tabla. De esta manera, las siguientes sentencias SELECT
producen el mismo resultado: devuelven todos los datos de la tabla Clientes.
SELECT DNI, Nombre, Apellido, Edad FROM Clientes
SELECT * FROM Clientes
Hasta ahora hemos seleccionado todas las tuplas de una tabla, restringiendo
nicamente los campos que obtenemos. Si deseamos, adems, poder restringir las
tuplas que nos devuelve una sentencia SELECT, debemos emplear la palabra
WHERE. La siguiente sentencia nos proporciona los nmeros de DNI de los clientes
menores de 30 aos:
SELECT DNI FROM Clientes WHERE Edad<30
JESS BOBADILLA SANCHO 125

Para obtener el apellido de los clientes menores de edad que se llaman
Jorge podemos escribir la sentencia:
SELECT Apellido FROM Clientes WHERE Edad<18 AND Nombre=Jorge
SQL permite incluir en sus condiciones los operadores <, <=, >, >=, <>,
AND, OR, NOT, IS NULL, IS NOT NULL, LIKE, BETWEEN AND, IN, ALL,
ANY, EXISTS, etc. La palabra LIKE funciona en combinacin con el carcter %,
que hace de comodn, por ejemplo, la siguiente sentencia selecciona todos los
atributos de la tabla Clientes en los que el campo Nombre comienza con la letra J.
SELECT * FROM Clientes WHERE Nombre LIKE J%
Si deseamos seleccionar todos los campos pertenecientes a las tuplas cuyos
atributos DNI se encuentran entre el 2000 y el 5000:
SELECT * FROM Clientes WHERE DNI BETWEEN 2000 AND 5000
El operador IN nos permite trabajar con un conjunto de valores. Por
ejemplo, para seleccionar los apellidos de los clientes que se llamen Jorge, Jess o
Elena, podemos usar las sentencias:
SELECT Apellido FROM Clientes WHERE Nombre=Jorge OR Nombre=Jess
OR Nombre=Elena
SELECT Apellido FROM Clientes WHERE Nombre IN (Jorge, Jess, Elena)

Para borrar tuplas utilizamos la sentencia DELETE, estableciendo las
condiciones que deseemos:
DELETE FROM Clientes WHERE Nombre =Jorge AND Apellido=Tejedor
DELETE FROM Clientes WHERE Edad >= 65
DELETE FROM Clientes WHERE Nombre NOT IN (Jorge)
La modificacin de datos se hace a travs de la sentencia UPDATE,
indicando con SET las modificaciones deseadas:
UPDATE Clientes SET Edad=15 WHERE DNI=5790
UPDATE Clientes SET Nombre=Ana WHERE Nombre=Elena
A continuacin se explica la manera de realizar selecciones utilizando varias
tablas relacionadas en una base de datos.

126 JESS BOBADILLA SANCHO
7.2.2 Trabajando con varias tablas
Con Sql podemos realizar consultas sobre varias tablas a la vez, para
unificar el contenido de las mismas; esto nos permite no repetir datos en varias
tablas. En nuestra base de datos no es necesario que en la tabla de pedidos est el
apellido del cliente. Simplemente bastar con que est el cdigo del cliente. De este
modo, podremos encontrar el resto de los datos buscando en la tabla de clientes el
cdigo correspondiente al pedido.
Pero trabajar con varias tablas nos origina un problema. Cmo
diferenciamos atributos con el mismo nombre en las distintas tablas? La solucin es
utilizar el nombre de la tabla antes de referenciar el campo. Por ejemplo, tenemos la
tabla Clientes y la tabla Pedidos y coinciden en el campo DNI: utilizaremos
Clientes.Codigo para referirnos a la tabla Clientes y Pedidos.Codigo para hacerlo a
la de Pedidos.
Antes de empezar a explicar cmo realizar accesos sobre varias tablas,
vamos a definir unas nuevas tablas que utilizaremos en los ejemplos de este
apartado. Tendremos tres tablas: la primera ser la de Clientes, que contendr los
campos Cdigo (cdigo de cliente), Nombre y Direccin. La tabla Productos
contendr los datos de los productos que existen en una tienda, tendr los campos
Referencia (referencia del producto), Nombre, Precio y Concepto (ej: kg, unidad,
par, etc...). Por lt imo, la tabla Pedidos contendr los pedidos de cada producto
realizados por los clientes, tendr los campos Cdigo (cdigo de cliente), Referencia
(referencia del producto) y Cantidad.

CLI ENTES
Cdigo Nombre Direccin
1 Luis Miguel Guzmn el Bueno, 90
2 Beatriz Zurriaga, 25
3 Jons Federico Puertas, 3
4 Joaqun Vinateros, 121
5 Pedro Virgen del Cerro, 154
6 Sandra Pablo Neruda, 15
7 Miguel Armadores, 1
8 Sergio Avenida del Ejercito,
76
9 Alejandro Leonor de Cortinas, 7
10 lvaro Fuencarral, 33
11 Roco Cervantes, 22
12 Joaqun Buenos Aires, 31
13 Jess Gaztambique, 32
JESS BOBADILLA SANCHO 127

PRODUCTOS
Referencia Nombre Precio Concepto
1 Patatas 200 Pta Kilo
2 Melones 500 Pta Kilo
3 Sandas 120 Pta Kilo
4 Zapatos 5.000 Pta Par
5 Chandal 12.000 Pta Unidad
6 Pantalones 2.000 Pta Unidad
7 Camisa 2.500 Pta Unidad
8 Corbata 950 Pta Unidad
9 Aceite 695 Pta Litro

PEDI DOS
Cdigo Referencia Cantidad
1 1 5
9 2 10
4 5 6
12 8 1
7 2 9
8 3 7
7 9 3
2 7 1
6 4 3
3 1 4

Un ejemplo sencillo consiste en seleccionar a partir de la tabla de pedidos
una lista con las direcciones a las que hay que enviar cada pedido y el nombre del
destinatario. Utilizaremos el campo Cdigo (cdigo de cliente) para unir las tablas
de Pedidos y Clientes. De este modo, cuando leamos un registro de la tabla de
pedidos, buscaremos en Clientes el registro cuyo campo Cdigo coincida con el de
Pedidos. Buscamos los pares de registros que coincidan por el campo Cdigo, para
ello utilizamos la siguiente sentencia:
SELECT Nombre, Direccin, Referencia, Cantidad FROM Clientes, Pedidos
WHERE Clientes.Cdigo = Pedidos.Cdigo

128 JESS BOBADILLA SANCHO
Seleccionamos los campos Nombre, Direccin, Referencia y Cantidad de
las tablas Clientes y Pedidos, donde el campo Cdigo del registro de clientes sea
igual al campo Cdigo del registro de Pedidos.
Advirtase cmo utilizamos el nombre de cada tabla para diferenciar el
campo Cdigo de Clientes y Pedidos; sin embargo, no es necesario utilizarlo cuando
hacemos referencia a los campos Direccin, Nombre o Cantidad, ya que esos
campos no se repiten en las dos tablas.

Nombre Direccin Referencia Cantidad
Luis Miguel Guzmn el Bueno, 90 1 5
Alejandro Leonor de Cortinas, 7 2 10
Joaqun Vinateros, 121 5 6
Joaqun Buenos Aires, 31 8 1
Miguel Armadores, 1 2 9
Sergio Avenida del Ejercito, 76 3 7
Miguel Armadores, 1 9 3
Beatriz Zurriaga, 25 7 1
Sandra Pablo Neruda, 15 4 3
Jons Federico Puertas, 3 1 4

La seleccin la hemos hecho sobre dos tablas, pero Sql nos permite utilizar
ms tablas con los operadores booleanos. De este modo podremos seleccionar sobre
varias tablas utilizando distintas condiciones para unirlas entre ellas de dos en dos.
Por ejemplo, si adems de los datos que hemos visto en el ejemplo anterior
queremos mostrar el nombre del producto que se pide, tendremos que utilizar una
tercera tabla, la de productos.
Ahora buscaremos tres registros, uno de cada tabla, en los que coincidan por
un lado el campo Cdigo de las tablas Pedidos y Clientes, y por otro el campo
Referencia de las tablas Pedidos y Productos. Como se puede ver, la tabla Pedidos
nos sirve de enlace entre las tablas Productos y Clientes, que no tienen ningn
campo en comn.
A continuacin vemos el resultado de esta seleccin, que nos muestra los
mismos registros que en el ejemplo anterior, pero sustituyendo el campo Referencia
por el del nombre del producto. Utilizaremos la siguiente sentencia Sql:
SELECT Clientes.Nombre, Direccin, Productos.Nombre, Cantidad FROM
Clientes, Productos, Pedidos WHERE Clientes.Cdigo = Pedidos.Cdigo AND
Pedidos.Referencia = Productos.Referencia

JESS BOBADILLA SANCHO 129

Nombre Direccin Producto Cantidad
Luis Miguel Guzmn el Bueno, 90 Patatas 5
Alejandro Leonor de Cortinas, 7 Melones 10
Joaqun Vinateros, 121 Chndal 6
Joaqun Buenos Aires, 31 Corbata 1
Miguel Armadores, 1 Melones 9
Sergio Avenida del Ejercito, 76 Sandas 7
Miguel Armadores, 1 Aceite 3
Beatriz Zurriaga, 25 Camisa 1
Sandra Pablo Neruda, 15 Zapatos 3
Jons Federico Puertas, 3 Patatas 4

En este caso s tenemos que utilizar el nombre de la tabla en el campo
Nombre, ya que lo tienen tanto la tabla Clientes como Productos, y no hacen
referencia a la misma cosa.
Utilizamos el operador booleano para que se cumplan las dos condiciones,
uniendo de este modo las tres tablas. Seleccionamos tres registros, uno de cada tabla.
Los registros de las tablas Clientes y Pedidos coinciden en el campo Cdigo, y los
de las tablas Pedidos y Productos coinciden en el campo Referencia.
A continuacin vamos a seleccionar los clientes que han comprado algo. No
es lo mismo que lo que hemos hecho en ejemplos anteriores, ya que en stos
mostrbamos todas las coincidencias que haba entre las dos tablas en el campo
Cdigo; esto generaba la repeticin de cada cliente tantas veces como pedidos tena.
En este nuevo ejemplo no deseamos que existan repeticiones. Cada cliente
que haya realizado una compra slo aparecer una vez. De este modo tendremos la
lista de los clientes que han comprado algo, sin ninguna repeticin. Para lograrlo
utilizaremos la clusula DISTINCT. Esta clusula hace que todos los registros
seleccionados sean distintos; de este modo, si aparece un cliente con dos pedidos,
solo se mostrar una vez, ya que los campos seleccionados (Nombre y Direccin),
coinciden en los dos pedidos.
SELECT DISTINCT Nombre, Direccin FROM Clientes, Pedidos WHERE
Clientes.Cdigo = Pedidos.Cdigo
Esta sentencia buscar las coincidencias de las tablas Pedidos y Clientes por
el campo Cdigo. Cuando encuentre varias veces el mismo cliente lo mostrar solo
una vez.

130 JESS BOBADILLA SANCHO
Una cosa importante que hay que tener en cuenta es que todos los campos
seleccionados debern ser iguales para todos los registros que unamos. Es decir, si
tenemos en dos registros dos nombres de cliente iguales pero direcciones diferentes,
se mostrarn los dos registros. Hay que tener cuidado con los campos que
seleccionemos, para que aparezcan los registros que deseemos.
Si queremos hacer ms restrictiva la seleccin y buscar solamente los
clientes que han comprado un producto, aadiremos una nueva condicin a la
sentencia:
SELECT DISTINCT Nombre, Direccin FROM Clientes, Pedidos WHERE
Clientes.Cdigo = Pedidos.Cdigo AND Referencia = 5
Podemos aadir todas las condiciones que deseemos a travs de los
operadores booleanos AND y OR. Estas condiciones podrn hacer referencia a
cualquiera de las tablas o, como en este ejemplo, mezclar campos de tablas.
Otra forma de seleccionar los clientes que han comprado un cierto producto
es a travs del operador EXISTS, de la siguiente forma:
SELECT Nombre, Direccin FROM Clientes WHERE EXIST (SELECT Cdigo
FROM Pedidos WHERE Clientes.Cdigo=Pedidos.Cdigo AND Referencia=2)
El operador EXISTS nos devolver los registros que se encuentren dentro de
la primera seleccin.

Nombre Direccin
Alejandro Leonor de Cortinas, 7
Beatriz Zurriaga, 25
Joaqun Buenos Aires, 31
Joaqun Vinateros, 121
Jons Federico Puertas, 3
Luis Miguel Guzmn el Bueno, 90
Miguel Armadores, 1
Sandra Pablo Neruda, 15
Sergio Avenida del Ejercito, 76

Seleccionar los clientes que todava no han comprado: vamos a hacer ahora
lo contrario que en el ejemplo anterior. Vamos a buscar los elementos de una tabla
que no se encuentran en otra. Para esto utilizaremos el operador IN que habamos
visto anteriormente, y ms concretamente NOT IN.
JESS BOBADILLA SANCHO 131

Buscamos los clientes cuyo cdigo no se encuentre en la tabla Pedidos. Para
esto, primero necesitaremos saber qu cdigos de cliente contiene la tabla de
pedidos. Como ya sabemos, lo conseguimos con la sentencia:
SELECT Cdigo FROM Pedidos
Una vez que hemos conseguido los cdigos, debemos comparar los registros
de la tabla Clientes, viendo en cada momento si el cdigo de cada registro est o no
en la seleccin previa que hemos realizado. Es decir,
SELECT Nombre, Direccin FROM Clientes WHERE Cdigo NOT IN
(Lista_de_cdigos)
Unido con lo anterior, tenemos que la sentencia Sql que utilizaremos ser la
siguiente:
SELECT Nombre, Direccin FROM Clientes WHERE Cdigo NOT IN (SELECT
Cdigo FROM Pedidos)
Ntese que en la seleccin que se hace sobre la tabla Pedidos slo se emplea
el campo Cdigo, ya que es el que queremos comparar.
Aplicando lo que acabamos de ver, podemos realizar la seleccin de los
clientes que han comprado alguna vez, utilizando el operador IN de la siguiente
forma:
SELECT Nombre, Direccin FROM Clientes WHERE Cdigo IN (SELECT
Cdigo FROM Pedidos)
Si quisiramos seleccionar los clientes que han comprado un producto
concreto, simplemente tendramos que hacer ms restrictiva la seleccin sobre
Pedidos:
SELECT Nombre, Direccin FROM Clientes WHERE Cdigo IN (SELECT
Cdigo FROM Pedidos WHERE Referencia = 5)

Nombre Direccin
Pedro Virgen del Cerro, 154
lvaro Fuencarral, 33
Roco Cervantes, 22
Jess Gaztambique, 32

Obtener el pedido con mayor nmero de unidades: vamos a ver cmo
utilizar los cuantificadores ALL y ANY. stos van siempre acompaados por un

132 JESS BOBADILLA SANCHO
operador de comparacin (<, >, =, <>, ...). Utilizaremos ALL y ANY para
seleccionar valores que sean mayor, menor, igual, etc.. que todos o alguno de los
valores de una seleccin previa.
Queremos seleccionar el pedido de mayor nmero de unidades, es decir, el
que tenga el campo Cantidad mayor. Para conseguirlo buscamos el registro cuyo
campo Cantidad sea mayor que el de todos los pedidos. Utilizamos, por tanto, el
cuantificador > ALL de la siguiente forma:
SELECT Nombre, Direccin, Referencia, Cantidad FROM Clientes, Pedidos
WHERE Cantidad >= ALL (SELECT Cantidad FROM Pedidos) AND
Clientes.Cdigo=Pedidos.Cdigo
Obsrvese que tenemos que utilizar tambin la condicin de que coincidan
los cdigos, ya que estamos utilizando dos tablas. Si no la utilizsemos, apareceran
todos los registros de la tabla de clientes con el valor del mayor pedido.
De la misma forma que hemos empleado ALL, podemos usar ANY. Este
segundo cuantificador lo utilizaremos para seleccionar valores que se encuentren en
algn campo. Por ejemplo, otra forma de seleccionar los clientes que han comprado
algo sera la siguiente:
SELECT Nombre, Direccin FROM Clientes WHERE Cdigo = ANY (SELECT
Cdigo FROM Pedidos)
As mismo, para seleccionar los clientes que no tienen ningn pedido
utilizaramos:
SELECT Nombre, Direccin FROM Clientes WHERE Cdigo <> ALL (SELECT
Cdigo FROM Pedidos)
Los operadores de comparacin no slo sirven para comparar campos
numricos, los podemos utilizar para comparar cualquier tipo de campo. Por
ejemplo, podemos utilizarlos para saber cul es el nombre menor, alfabticamente
hablando:
SELECT Nombre FROM Clientes WHERE Nombre <= ALL (SELECT Nombre
FROM Clientes)

Nombre Direccin Referencia Cantidad
Alejandro Leonor de Cortinas, 7 2 10


JESS BOBADILLA SANCHO 133

7.3 ARQUITECTURA DE UNA APLICACIN
Una aplicacin Java que realiza accesos a bases de datos funciona segn una
arquitectura que permite escribir los programas abstrayndose de los detalles de los
niveles inferiores (discos, drivers, sistema operativo, etc.).
En la siguiente figura se muestran los niveles ms importantes y conocidos
del esquema de funcionamiento con bases de datos: en el nivel superior se
encuentran las aplicaciones que realizamos; estas aplicaciones son interpretadas por
la mquina virtual Java (JVM).








El sistema operativo proporciona el nivel de entrada/salida, que interacta
con los dispositivos fsicos donde se encuentran las bases de datos (que pueden ser
de diferentes tipos). El sistema operativo tambin gestiona el nivel de ODBC (Open
Data Base Conectivity); ODBC nos permite utilizar un interfaz nico para los
distintos tipos de bases de datos, adems de proporcionar nombres lgicos que se
relacionan con los nombres fsicos que tendrn los ficheros. En nuestros programas
utilizaremos siempre nombres lgicos, abstrayndonos de esta manera de futuros
cambios en los niveles inferiores. En el siguiente apartado se muestra la manera de
configurar ODBC en Windows.
El siguiente grfico incide en la arquitectura del sistema vista desde el nivel
de aplicacin, usando Java. El tubo que se ha dibujado representa a la clase
Connection, que nos proporciona el medio para comunicarnos con las bases de
datos. Segn cual sea el tipo de la base de datos, los drivers sern diferentes, por lo
que en primer lugar creamos un objeto de tipo DriverManager y, a travs de l, el
objeto Connection.
Oracle

Access

MSQL

Sistema Operativo
ODBC

Aplicacin

JVM


134 JESS BOBADILLA SANCHO












Una vez que disponemos de la conexin adecuada, el funcionamiento es
muy simple: creamos una instancia de la clase Statement y la utilizamos para definir
las sentencias SQL adecuadas en nuestra aplicacin. Estas sentencias SQL
proporcionarn, en general, una serie de datos provenientes de la base de datos, que
se almacenan en una instancia del objeto ResultSet.
Resumimos la forma de actuar:
La programacin se realiza siguiendo las lneas discontinuas del grfico:
creacin de un objeto de tipo DriverManager; a travs de l se crea un
objeto de tipo Connection, que a su vez usamos para crear un objeto
Statement; finalmente, usando el objeto Statement obtenemos un objeto
ResultSet, donde se encuentran los resultados deseados.

En tiempo de ejecucin, la sentencia SQL se ejecuta descendiendo a
travs del objeto Connection y el resultado asciende al nivel de aplicacin,
almacenndose en un objeto de tipo ResultSet. Ms adelante detallaremos la
manera de acceder a los datos (atributos) almacenados en el objeto
ResultSet.
Oracle

Access

MSQL

ODBC

SELECT * FROM ...
ResultSet
Statement
Connection

DriverManager

JESS BOBADILLA SANCHO 135

7.4 CONEXIN A UNA BASE DE DATOS
Para poder acceder desde el nivel de aplicacin a una base de datos ya
existente, debemos administrar los orgenes de datos ODBC.
En este primer ejemplo vamos a utilizar una base de datos de tipo Access,
cuyo nombre fsico es EjemploBD.mdb, y est situada en el directorio
C:\Jesus\ProyectosJava\Libro\BD. Hemos decidido asignarle el nombre lgico
NombreLogico, que aunque no identifica su funcin, tiene el inters didctico de
remarcar en los programas el hecho de que no emplearemos nombres fsicos en el
nivel de aplicacin al trabajar con bases de datos.
Los dos siguientes grficos muestran la configuracin que hemos empleado
en ODBC. Si la base de datos se utiliza en un sistema multiusuario (como por
ejemplo en una aplicacin web), debemos utilizar la solapa DSN de Sistema.














136 JESS BOBADILLA SANCHO
A continuacin se presenta la clase PruebaConexion, en la que
estableceremos una conexin a la base de datos que previamente hemos preparado
en el administrador de ODBC. Tambin se crea el objeto Statement y el ResultSet,
aunque, en este primer ejemplo, no actuaremos sobre los atributos obtenidos en el
objeto ResultSet.
La clase PruebaConexion (lnea 3) nos va a servir de plantilla para la
realizacin de las futuras aplicaciones Java con acceso a bases de datos. Las clases e
interfaces que utilizaremos se encuentran en el paquete java.sql (lnea 1).
Primero establecemos el driver que vamos a utilizar, llamando al mtodo
esttico forName, perteneciente a la clase Class (lnea 7). El driver que empleamos
es el ODBC que nos proporciona la biblioteca JDBC.
Para crear la conexin, en primer lugar establecemos la fuente de donde
provienen los datos (en nuestro caso la base de datos). Utilizaremos el nombre
lgico que habamos preparado en el administrador de ODBC (lnea 8).
Posteriormente, en las lneas 9 y 10, hacemos uso del mtodo getConnection
perteneciente a la clase DriverManager, aplicado al nombre lgico de la fuente de
datos. Si se desea, se puede hacer uso del mtodo getConnection de la clase
DataSource, en lugar del de la clase DriverManager.
Utilizando el mtodo createStatement, perteneciente al objeto de tipo
Connection, creamos el objeto de tipo Statement (lnea 11). Ya estamos en
condiciones de obtener los datos deseados de la base de datos: nos basta con crear un
objeto de tipo ResultSet (lneas 12 y 13) ejecutando el mtodo executeQuery,
perteneciente al interfaz Statement. Como argumento del mtodo executeQuery
podemos colocar la sentencia SELECT, de tipo SQL, que nos convenga. Obsrvese
que la sentencia SELECT que hemos utilizado recoge todos los campos de la tabla
DatosPersonales.
En los ejemplos del siguiente apartado veremos como extraer los datos
(atributos) del objeto Personas, de tipo ResultSet.

1 import java.sql.*;
2
3 public class PruebaConexion {
4
5 public static void main(String[] args){
6 try{
7 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
8 String BaseDeDatos = "jdbc:odbc:NombreLogico";
9 Connection Conexion =
10 DriverManager.getConnection(BaseDeDatos);
11 Statement SentenciaSQL = Conexion.createStatement();
JESS BOBADILLA SANCHO 137

12 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
13 * FROM DatosPersonales");
14
15 Personas.close();
16 Conexion.close();
17 SentenciaSQL.close();
18 }
19 catch (ClassNotFoundException e) {
20 System.out.println("Clase no encontrada");
21 }
22 catch (SQLException e) {
23 System.out.println(e);
24 }
25
26 System.out.println("Sin error al conectar");
27 }
28
29 }
En las lneas 15 a 17 se realiza una liberacin explcita de los recursos
empleados, utilizando los mtodos close que proporcionan los interfaces ResultSet,
Connection y Statement.
En las lneas 19 a 24 se recogen las excepciones que podran levantarse
debido a las instanciaciones realizadas y a los mtodos invocados.


7.5 OBTENCIN DE LOS DATOS CONTENIDOS EN UN
OBJETO DE TIPO RESULTSET
En este apartado se explica, en primer lugar, el significado y uso de la clase
ResultSet, incidiendo en los mtodos que se utilizan habitualmente en las
aplicaciones Java con acceso a bases de datos; posteriormente se desarrolla un
ejemplo que completa a la clase PruebaConexion, proporcionando un listado de
todos los datos contenidos en una tabla.
Los ejemplos de este captulo se van a basar en las posibilidades que
proporciona el interfaz ResultSet, empleando un modelo de funcionamiento muy
similar al del cdigo proporcionado.


138 JESS BOBADILLA SANCHO
7.5.1 El interfaz ResultSet
Los objetos ResultSet permiten recoger los resultados de la ejecucin de
sentencias SQL; estos resultados proporcionan un nmero variable de columnas y de
filas. En definitiva, un ResultSet es un contenedor tabular de tamao variable.
Cada objeto de tipo ResultSet contiene un cursor que inicialmente se
encuentra situado en la posicin anterior a la primera fila de la tabla. Existe una serie
de mtodos que nos permiten mover el cursor a lo largo de la tabla. La siguiente
figura muestra grficamente dichos mtodos:

DNI Nombre Apellido Edad
53023767A Pedro Rubio 18
84604568K Ana Moreno 35
82607936G Carmen Delgado 12
77459822P Luis Tejedor 47
2376856S Jorge Gil 21


Todos los mtodos sealados devuelven un valor de tipo boolean, que nos
indica si el movimiento del cursor ha sido posible. Hay que tener en cuenta que, por
defecto, los objetos RecordSet nicamente pueden ser recorridos incrementalmente,
y que adems no son actualizables (no se pueden modificar sus atributos). En los
siguientes apartados realizaremos una leve modificacin a nuestros programas para
solventar estas restricciones.
Una vez situado el cursor en la posicin deseada, disponemos de una gran
cantidad de mtodos para conocer su posicin (isXxxxx), consultar el valor de los
atributos (getXxxxx) o modificar los mismos (updateXxxxx):

DNI Nombre Apellido Edad
53023767A Pedro Rubio 18
84604568K Ana Moreno 35
82607936G Carmen Delgado 12
77459822P Luis Tejedor 47
2376856S Jorge Gil 21


first()
last()
beforeFirst()
afterLast()
absolute(2)
1

2

Cursor

relative(-1)
next()
previous()
isFirst()
isLast()
isBeforeFirst()
isAfterLast()
1
2

Cursor

getString(...)

getInt(...)

updateString(...)

updateInt(...)

JESS BOBADILLA SANCHO 139

Tanto los mtodos update como los mtodos get estn sobrecargados
para admitir dos tipos de argumentos: el nombre de la columna o la posicin de la
columna; de esta manera disponemos, por ejemplo, de un mtodo getInt(String
NombreColumna), y de otro mtodo getInt(int IndiceColumna). Las columnas se
numeran empezando por 1:
En el RecordSet de ejemplo, los siguientes dos mtodos producen el mismo
resultado (Luis): getString(Nombre) y getString(2).
Los mtodos get se aplican a una gran variedad de tipos de datos: Array,
AsciiStream, BigDecimal, BinaryStream, Boolean, Byte, Bytes, Date, Double, Float,
Int, Long, Object, Ref, Short, String, Time, Timestamp, URL, etc. formando
getArray(...), getByte(...), etc. Los mtodos update existen para la mayor parte de
estos tipos de datos.

7.5.2 Hola mundo
Vamos a completar el ejemplo anterior (PruebaConexion), para obtener los
listados deseados de los datos contenidos en el objeto Personas, de tipo ResultSet.
Partiremos de la tabla DatosPersonales, que contiene la siguiente informacin:

DNI Nombre Apellido Edad
53023767A Pedro Rubio 18
84604568K Ana Moreno 35
82607936G Carmen Delgado 12
77459822P Luis Tejedor 47
22376856S Jorge Gil 21

La clase Listado (lnea 3) realiza una conexin con la base de datos
NombreLogico y extrae todos sus atributos, copindolos en el objeto Personas
(lneas 9 a 15), tal y como se realiz en el ejemplo anterior.
Para iterar por todas las tuplas (filas) del RecordSet Personas, empleamos
un bucle while (lnea 16) que finaliza cuando el mtodo next devuelve el valor false,
indicando el final del RecordSet.
Por cada tupla se obtienen los atributos alfanumricos de los campos DNI,
Nombre y Apellido (lneas 17 a 19), empleando el mtodo getString. Tambin se
obtiene el atributo del campo Edad, de tipo entero, por lo que se utiliza el mtodo
getInt (lnea 20).

140 JESS BOBADILLA SANCHO
En las lneas 21 y 22 se imprime por consola los resultados obtenidos en la
tupla en la que se encuentra el puntero del objeto personas. La clase Listado se
puede considerar como el programa HolaMundo de las bases de datos.

1 import java.sql.*;
2
3 public class Listado {
4
5 public static void main(String[] args){
6 String Nombre,Apellido,DNI;
7 int Edad;
8 try{
9 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
10 String BaseDeDatos = "jdbc:odbc:NombreLogico";
11 Connection Conexion =
12 DriverManager.getConnection(BaseDeDatos);
13 Statement SentenciaSQL = Conexion.createStatement();
14 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
15 * FROM DatosPersonales");
16 while (Personas.next()) {
17 DNI = Personas.getString("DNI");
18 Nombre = Personas.getString("Nombre");
19 Apellido = Personas.getString("Apellido");
20 Edad = Personas.getInt("Edad");
21 System.out.println(Nombre+" "+Apellido+", "+
22 Edad+", "+DNI);
23 }
24 Personas.close();
25 Conexion.close();
26 SentenciaSQL.close();
27 }
28 catch (ClassNotFoundException e) {
29 System.out.println("Clase no encontrada");
30 }
31 catch (SQLException e) {
32 System.out.println(e);
33 }
34 }
35
36 }



JESS BOBADILLA SANCHO 141

Si cambiamos la sentencia SQL a: SELECT * FROM DatosPersonales
WHERE Edad<23, obtenemos el resultado:



Poniendo la siguiente sentencia SQL: SELECT * FROM
DatosPersonales WHERE Edad<23 ORDER BY Apellido, obtenemos el
resultado:





7.6 MODIFICACIN, INSERCIN Y BORRADO
Cuando deseamos recorrer un objeto de tipo ResultSet en orden no
ascendente o bien modificar el contenido del mismo, debemos proporcionar ciertos
argumentos al mtodo createStatement, perteneciente al interfaz Connection.
El interfaz ResultSet proporciona, entre otros campos, los valores estticos
de tipo entero: TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE,
TYPE_SCROLL_SENSITIVE, CONCUR_READ_ONLY y CONCUR_UPDATABLE.
Si deseamos poder mover el cursor hacia delante y hacia atrs, evitaremos el uso de
TYPE_FORWARD_ONLY. Si queremos poder modificar el RecordSet,
seleccionaremos CONCUR_UPDATABLE.
Entre las tres posibilidades que ofrece el mtodo createStatement, se
encuentra la ya utilizada (sin parmetros) y la opcin de dos parmetros enteros: el
primero para indicar el TYPE_SCROLL y el segundo para indicar el CONCUR.
A partir de ahora haremos uso del mtodo createStatement de la siguiente manera:

Statement SentenciaSQL = Conexion.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);

142 JESS BOBADILLA SANCHO
7.6.1 Modificacin
La clase Modificacion (lnea 3) sigue el esquema explicado para establecer
una conexin con la base de datos (lneas 9 a 17); en este caso con capacidad para
mover el cursor en cualquier direccin y para modificar los datos del RecordSet
(lneas 13 a 15).
En la lnea 19 iteramos secuencialmente por el RecordSet Personas,
obteniendo los atributos del Nombre y Apellido en cada tupla (lneas 20 y 21). Si el
nombre y apellidos hallados en una iteracin coincide con el de Ana Moreno,
modificamos este valor por: 47645876F, Luis, Reverte, 45.
Obsrvese el uso que realizamos de los mtodos updateString(...) y
updateInt(...) en las lneas 26 a 29, que debemos combinar con el mtodo updateRow
(lnea 30), para que las modificaciones se realicen fsicamente en la base de datos.
Como se avisa en las lneas 24 y 25, debemos obligatoriamente invocar a un
mtodo update por cada mtodo get que utilicemos; es decir, debemos actualizar
cada campo (columna) que consultemos.

1 import java.sql.*;
2
3 public class Modificacion {
4
5 public static void main(String[] args){
6 String Nombre,Apellido,DNI;
7 int Edad;
8 try{
9 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
10 String BaseDeDatos = "jdbc:odbc:NombreLogico";
11 Connection Conexion =
12 DriverManager.getConnection(BaseDeDatos);
13 Statement SentenciaSQL = Conexion.createStatement(
14 ResultSet.TYPE_SCROLL_INSENSITIVE,
15 ResultSet.CONCUR_UPDATABLE);
16 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
17 * FROM DatosPersonales");
18
19 while (Personas.next()) {
20 Nombre = Personas.getString("Nombre");
21 Apellido = Personas.getString("Apellido");
22 if (Apellido.equalsIgnoreCase("Moreno")&&
23 Nombre.equalsIgnoreCase("Ana")){
24 // IMPORTANTE: por cada getXxxxx("Campo") hay que
25 // realizar un updateXxxxx("Campo")
26 Personas.updateString("Nombre","Luis");
JESS BOBADILLA SANCHO 143

27 Personas.updateString("Apellido","Reverte");
28 Personas.updateInt("Edad",45);
29 Personas.updateString("DNI","47645876F");
30 Personas.updateRow();
31 System.out.println("Registro modificado");
32 break;
33 }
34 }
35
36 Personas.close();
37 Conexion.close();
38 SentenciaSQL.close();
39 }
40 catch (ClassNotFoundException e) {
41 System.out.println("Clase no encontrada");
42 }
43 catch (SQLException e) {
44 System.out.println(e);
45 }
46 }
47
48 }

La siguiente secuencia de comandos muestra el correcto funcionamiento de
nuestro programa:










144 JESS BOBADILLA SANCHO
7.6.2 Insercin
En la clase Insercion (lnea 3) se muestra de una manera muy sencilla la
forma de incluir un nuevo registro (tupla) en una base de datos. Las lneas 7 a 15 se
encargan de crear una conexin con capacidad para modificar la tabla
(CONCUR_UPDATABLE).
En la lnea 17 nos movemos a la posicin de insercin, utilizando el mtodo
moveToInsertRow, que pertenece al interfaz ResultSet. La posicin actual del cursor
se guarda automticamente y puede ser restaurada utilizando el mtodo
moveToCurrentRow (lnea 23); la lnea de insercin es un buffer asociado a un
ResultSet modificable.
Una vez situados en la posicin de insercin, debemos definir el contenido
de todos los campos, utilizando los mtodos updateXxxx requeridos (lneas 18 a
21). Finalmente, utilizamos el mtodo insertRow (lnea 22) para aadir fsicamente
el registro en el RecordSet y en la base de datos.
Obsrvese como en la lnea 19 se utiliza como argumento el nmero del
campo en el RecordSet, en lugar del nombre del mismo. Podemos emplear ambas
posibilidades segn nos convenga, atendiendo a las caractersticas de la aplicacin.
En todo el proceso de insercin es necesario cumplir una serie de
restricciones:
Cuando nos encontramos en la posicin de insercin (tras ejecutar el mtodo
moveToInsertRow), solo podemos utilizar los mtodos getXxxx,
updateXxxx e insertRow.
Todos los campos deben tener un valor antes de utilizar el mtodo
insertRow.
En cada campo, debe utilizarse un mtodo updateXxxx antes de poder
hacer uso del correspondiente getXxxxx.

1 import java.sql.*;
2
3 public class Insercion {
4
5 public static void main(String[] args){
6 try{
7 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
8 String BaseDeDatos = "jdbc:odbc:NombreLogico";
9 Connection Conexion =
10 DriverManager.getConnection(BaseDeDatos);
11 Statement SentenciaSQL = Conexion.createStatement(
JESS BOBADILLA SANCHO 145

12 ResultSet.TYPE_SCROLL_INSENSITIVE,
13 ResultSet.CONCUR_UPDATABLE);
14 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
15 * FROM DatosPersonales");
16
17 Personas.moveToInsertRow();
18 Personas.updateString("DNI","50839979M");
19 Personas.updateString(2,"Pedro");
20 Personas.updateString("Apellido","Cela");
21 Personas.updateInt("Edad",78);
22 Personas.insertRow();
23 // Personas.moveToCurrentRow();
24
25 Personas.close();
26 Conexion.close();
27 SentenciaSQL.close();
28 }
29 catch (ClassNotFoundException e) {
30 System.out.println("Clase no encontrada");
31 }
32 catch (SQLException e) {
33 System.out.println(e);
34 }
35 }
36
37 }

En la siguiente secuencia de ejecuciones se puede observar la insercin del
registro Pedro Cela 78 50839979M, tal y como se ha definido en las lneas 18 a
21).







146 JESS BOBADILLA SANCHO
7.6.3 Borrado
En el siguiente ejemplo buscamos a travs de la tabla DatosPersonales el
registro que hemos aadido en el apartado anterior (Pedro Cela), para borrarlo.
La creacin de los objetos Connection, Statement y ResultSet se realiza de la
manera habitual (lneas 8 a 16). La bsqueda del registro emplea estructuras ya
utilizadas: bucle en la lnea 18, obtencin de atributos en las lneas 19 y 20, y
comparacin con los datos buscados en las lneas 21 y 22.
La manera de borrar un registro en una tabla es muy simple: en primer lugar
situamos el cursor en el registro y luego utilizamos el mtodo deleteRow (lnea 24).
El mtodo deleteRow borra el registro en el recordSet y en la base de datos; no
podemos aplicar este mtodo cuando el cursor est situado en la posicin de
insercin.

1 import java.sql.*;
2
3 public class Borrado {
4
5 public static void main(String[] args){
6 String Nombre,Apellido;
7 try{
8 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
9 String BaseDeDatos = "jdbc:odbc:NombreLogico";
10 Connection Conexion =
11 DriverManager.getConnection(BaseDeDatos);
12 Statement SentenciaSQL = Conexion.createStatement(
13 ResultSet.TYPE_SCROLL_INSENSITIVE,
14 ResultSet.CONCUR_UPDATABLE);
15 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
16 * FROM DatosPersonales");
17
18 while (Personas.next()) {
19 Nombre = Personas.getString("Nombre");
20 Apellido = Personas.getString("Apellido");
21 if (Apellido.equalsIgnoreCase("Cela")&&
22 Nombre.equalsIgnoreCase("Pedro")){
23 System.out.println("Registro eliminado");
24 Personas.deleteRow();
25 break;
26 }
27 }
28 Personas.close();
29 Conexion.close();
JESS BOBADILLA SANCHO 147

30 SentenciaSQL.close();
31 }
32 catch (ClassNotFoundException e) {
33 System.out.println("Clase no encontrada");
34 }
35 catch (SQLException e) {
36 System.out.println(e);
37 }
38 }
39
40 }










7.7 APLICACIN DE MANTENIMIENTO DE LOS DATOS
DE UNA TABLA
7.7.1 Arquitectura de la aplicacin
Basndonos en los ejemplos explicados anteriormente, vamos a desarrollar
una aplicacin que nos permita realizar un mantenimiento (altas, bajas,
modificaciones, consulta y listado) de los datos contenidos en la tabla
DatosPersonales.

148 JESS BOBADILLA SANCHO
Las clases que hemos desarrollado en los apartados precedentes van a
convertirse en objetos reutilizables (que denominaremos ObXxxxx). El cdigo de
estos objetos se mantendr prcticamente igual que el de las clases originales, lo que
permitir que este ejemplo se entienda con mucha facilidad.
El mantenimiento de la tabla se realizar a travs de un interfaz grfico de
usuario (GUI) que implementamos en la clase GUIAccesoBD y que ponemos en
ejecucin gracias al mtodo main de la clase PruebaAccesoBD.
Resulta muy adecuado crear una clase que encapsule los campos de la tabla,
con el objetivo de que en cada instancia de esa clase se pueda definir una fila
(registro) del RecordSet. La clase del ejemplo que realiza esta funcin es
ObRegistro.











7.7.2 Abstraccin de datos
El encapsulamiento de los datos lo realiza la clase ObRegistro. Los objetos
de tipo ObRegistro contienen las propiedades DNI, Nombre, Apellido y Edad (lneas
2 y 3), que coinciden con los campos de la tabla DatosPersonales.
ObRegistro

ObPosicionamiento

ObConsulta

ObBorrado

ObInserccion

ObListado

ObModificacion

PruebaAccesoBD

GUIAccesoBD

JESS BOBADILLA SANCHO 149

Para asignar valores a las propiedades disponemos del constructor situado en
la lnea 5. Los datos se pueden obtener individualmente gracias a los mtodos de
acceso (DameXxxx) definidos en las lneas 13, 17, 21 y 25.

1 public class ObRegistro {
2 private String DNI, Nombre, Apellido;
3 private int Edad;
4
5 ObRegistro (String DNI, String Nombre, String Apellido,
6 int Edad) {
7 this.DNI = DNI;
8 this.Nombre = Nombre;
9 this.Apellido = Apellido;
10 this.Edad = Edad;
11 }
12
13 String DameDNI() {
14 return DNI;
15 }
16
17 String DameNombre() {
18 return Nombre;
19 }
20
21 String DameApellido() {
22 return Apellido;
23 }
24
25 int DameEdad() {
26 return Edad;
27 }
28
29 }


7.7.3 Insercin
La clase ObInserccion nos proporciona un buen ejemplo de la conveniencia
de abstraer los datos en un objeto, as como de la facilidad con la que se pueden
entender los objetos de este apartado una vez que hemos asimilado los de los
apartados anteriores.

150 JESS BOBADILLA SANCHO
La insercin de datos utilizando esta clase se consigue al crear instancias de
la misma. El constructor situado en la lnea 5 recoge un objeto de tipo ObRegistro e
introduce sus datos individuales en los campos de la tabla (lneas 18 a 22).
Entre la llamada al mtodo moveToInsertRow (lnea 17) y la llamada al
mtodo insertRow (lnea 23), utilizamos los mtodos updateXxxx adecuados,
proporcionando los datos individuales contenidos en el objeto Datos de tipo
ObRegistro (lnea 5).
El resto del cdigo ha sido tomado, sin ninguna modificacin, de la clase
Insercion, explicada en apartados anteriores.

1 import java.sql.*;
2
3 public class ObInserccion {
4
5 ObInserccion(ObRegistro Datos){
6 try{
7 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
8 String BaseDeDatos = "jdbc:odbc:NombreLogico";
9 Connection Conexion =
10 DriverManager.getConnection(BaseDeDatos);
11 Statement SentenciaSQL = Conexion.createStatement(
12 ResultSet.TYPE_SCROLL_INSENSITIVE,
13 ResultSet.CONCUR_UPDATABLE);
14 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
15 * FROM DatosPersonales");
16
17 Personas.moveToInsertRow();
18 Personas.updateString("DNI", Datos.DameDNI());
19 Personas.updateString("Nombre",Datos.DameNombre());
20 Personas.updateString("Apellido",
21 Datos.DameApellido());
22 Personas.updateInt("Edad",Datos.DameEdad());
23 Personas.insertRow();
24
25 Personas.close();
26 Conexion.close();
27 SentenciaSQL.close();
28 }
29 catch (ClassNotFoundException e) {
30 System.out.println("Clase no encontrada");
31 }
32 catch (SQLException e) {
33 System.out.println(e);
34 }
35 } }
JESS BOBADILLA SANCHO 151

7.7.4 Consulta
En esta aplicacin, los datos se podrn consultar proporcionando el DNI de
la persona; de esta manera, el constructor de la clase ObConsulta (lnea 8) admite un
parmetro de tipo String a travs del que se proporcionan argumentos con
identificadores de DNI.
Cuando se crea una instancia de la clase ObConsulta, el valor del DNI
suministrado (DNIPedido) se compara con el DNI obtenido en cada registro de la
tabla (lneas 18 a 20); en caso de encontrarse una coincidencia se obtiene la posicin
del cursor, empleando el mtodo getRow (lnea 21), y se guarda en la propiedad
privada Posicion (lnea 5).
En las lneas 22 a 24 se obtienen los atributos del registro hallado, y en las
lneas 25 y 26 se insertan estos valores en el objeto DatosPersona, de tipo
ObRegistro (lnea 6).
Los mtodos pblicos PosicionEncontrada (lnea 43) y DameDatos (lnea
47) nos permiten acceder, desde el exterior, a las propiedades privadas Posicion y
DatosPersona. De esta manera, tras una consulta, podemos obtener los datos
deseados, adems de la posicin en la que se encuentran, con el fin de visualizarlos,
borrarlos o modificarlos.

1 import java.sql.*;
2
3 public class ObConsulta {
4
5 private int Posicion = 0;
6 private ObRegistro DatosPersona;
7
8 ObConsulta(String DNIPedido){
9 try{
10 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
11 String BaseDeDatos = "jdbc:odbc:NombreLogico";
12 Connection Conexion =
13 DriverManager.getConnection(BaseDeDatos);
14 Statement SentenciaSQL = Conexion.createStatement();
15 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
16 * FROM DatosPersonales");
17
18 while (Personas.next()) {
19 String DNI = Personas.getString("DNI");
20 if (DNI.equalsIgnoreCase(DNIPedido)){
21 Posicion = Personas.getRow();
22 String Nombre = Personas.getString("Nombre");

152 JESS BOBADILLA SANCHO
23 String Apellido = Personas.getString("Apellido");
24 int Edad = Personas.getInt("Edad");
25 DatosPersona = new
26 ObRegistro(DNI,Nombre,Apellido,Edad);
27 break;
28 }
29
30 }
31 Personas.close();
32 Conexion.close();
33 SentenciaSQL.close();
34 }
35 catch (ClassNotFoundException e) {
36 System.out.println("Clase no encontrada");
37 }
38 catch (SQLException e) {
39 System.out.println(e);
40 }
41 }
42
43 public int PosicionEncontrada() {
44 return Posicion;
45 }
46
47 public ObRegistro DameDatos() {
48 return DatosPersona;
49 }
50
51 }


7.7.5 Modificacin
La modificacin de datos se realiza a travs de la clase ObModificacion
(lnea 3). Al crear una instancia de la clase (lnea 5) se debe proporcionar la posicin
del registro que deseamos variar y los nuevos valores que pretendemos incluir.
Conociendo la posicin del registro a modificar (PosicionBuscada) resulta
inmediato situar el cursor en el mismo; basta con hacer uso del mtodo absolute
(lnea 17). Posteriormente actualizamos cada campo, obteniendo los nuevos valores
del parmetro Datos (lneas 18 a 21). Finalmente forzamos la escritura en la base de
datos, empleando el mtodo updateRow (lnea 22).
JESS BOBADILLA SANCHO 153


1 import java.sql.*;
2
3 public class ObModificacion {
4
5 ObModificacion(int PosicionBuscada, ObRegistro Datos) {
6 try{
7 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
8 String BaseDeDatos = "jdbc:odbc:NombreLogico";
9 Connection Conexion =
10 DriverManager.getConnection(BaseDeDatos);
11 Statement SentenciaSQL = Conexion.createStatement(
12 ResultSet.TYPE_SCROLL_INSENSITIVE,
13 ResultSet.CONCUR_UPDATABLE);
14 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
15 * FROM DatosPersonales");
16
17 Personas.absolute(PosicionBuscada);
18 Personas.updateString("DNI",Datos.DameDNI());
19 Personas.updateString("Nombre",Datos.DameNombre());
20 Personas.updateString("Apellido",Datos.DameApellido());
21 Personas.updateInt("Edad",Datos.DameEdad());
22 Personas.updateRow();
23
24 Personas.close();
25 Conexion.close();
26 SentenciaSQL.close();
27 }
28 catch (ClassNotFoundException e) {
29 System.out.println("Clase no encontrada");
30 }
31 catch (SQLException e) {
32 System.out.println(e);
33 }
34 }
35
36 }



154 JESS BOBADILLA SANCHO
7.7.6 Borrado
La clase encargada de borrar los datos (obBorrado) resulta realmente
sencilla: su nico constructor (lnea 5) admite un parmetro que indica la posicin de
la tabla que se desea borrar (PosicionBuscada). En la lnea 17 nos situamos en la
posicin deseada, empleando el mtodo absolute; en la lnea 18 borramos el registro
en el RecordSet y en la base de datos, usando el mtodo deleteRow.

1 import java.sql.*;
2
3 public class ObBorrado {
4
5 ObBorrado(int PosicionBuscada){
6 try{
7 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
8 String BaseDeDatos = "jdbc:odbc:NombreLogico";
9 Connection Conexion =
10 DriverManager.getConnection(BaseDeDatos);
11 Statement SentenciaSQL = Conexion.createStatement(
12 ResultSet.TYPE_SCROLL_INSENSITIVE,
13 ResultSet.CONCUR_UPDATABLE);
14 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
15 * FROM DatosPersonales");
16
17 Personas.absolute(PosicionBuscada);
18 Personas.deleteRow();
19
20 Personas.close();
21 Conexion.close();
22 SentenciaSQL.close();
23 }
24 catch (ClassNotFoundException e) {
25 System.out.println("Clase no encontrada");
26 }
27 catch (SQLException e) {
28 System.out.println(e);
29 }
30 }
31
32 }



JESS BOBADILLA SANCHO 155

7.7.7 Listado
La clase ObListado proviene de la clase Listado; se proporciona un
constructor (lnea 6) que admite un componente de tipo TextArea, en el que se
escribir el contenido de la tabla.
Antes de recorrer la tabla borramos la informacin existente en el objeto
AreaDeListado (lnea 17). En cada iteracin del bucle (lnea 19) obtenemos los
valores de los campos (lneas 20 a 23), la posicin del registro (lnea 24) utilizando
el mtodo getRow, y por fin aadimos estos datos al rea de texto (lneas 27 y 28),
haciendo uso del mtodo append sobre el componente AreaDeListado.

1 import java.sql.*;
2 import java.awt.TextArea;
3
4 public class ObListado {
5
6 ObListado(TextArea AreaDeListado){
7 String DNI, Nombre, Apellido, Linea;
8 int Edad, Posicion;
9 try{
10 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
11 String BaseDeDatos = "jdbc:odbc:NombreLogico";
12 Connection Conexion =
13 DriverManager.getConnection(BaseDeDatos);
14 Statement SentenciaSQL = Conexion.createStatement();
15 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
16 * FROM DatosPersonales");
17 AreaDeListado.setText("");
18
19 while (Personas.next()) {
20 DNI = Personas.getString("DNI");
21 Nombre = Personas.getString("Nombre");
22 Apellido = Personas.getString("Apellido");
23 Edad = Personas.getInt("Edad");
24 Posicion = Personas.getRow();
25 Linea = DNI+", "+Nombre+" "+Apellido+",
26 "+String.valueOf(Edad);
27 AreaDeListado.append(String.valueOf(Posicion)+":
28 "+Linea+"\n");
29 }
30
31 Personas.close();
32 Conexion.close();
33 SentenciaSQL.close();
34 }
35 catch (ClassNotFoundException e) {

156 JESS BOBADILLA SANCHO
36 System.out.println("Clase no encontrada");
37 }
38 catch (SQLException e) {
39 System.out.println(e);
40 }
41 }
42
43 }

7.7.8 Posicionamiento
En buena parte de las clases anteriores hemos trabajado con la posicin del
cursor en la tabla. La clase ObPosicionamiento nos permite modificar dicho cursor a
partir de la posicin actual (que suministramos como parmetro en el constructor).
Hay que tener en cuenta que en todas las clases suministradas, la base de datos se
cierra despus de realizar las acciones pertinentes (insercin, modificacin, ...), por
lo que la posicin del cursor de la tabla se pierde; esta es la razn por la que
debemos guardar esta posicin en un mbito superior y pasarla a la clase a travs del
parmetro Posicion del constructor (lnea 8).
Las posibilidades de movimiento del cursor programadas son:

Parmetro
Accion
Movimiento en la
tabla
Mtodo Lnea de
cdigo
0 ltima posicin last() 29
1 Primera posicin first() 32
2 5 posiciones menos relative(-5) 35
3 Anterior previous() 38
4 Siguiente next() 41
5 5 posiciones ms relative(+5) 44
Los mtodos de posicionamiento del cursor devuelven un valor lgico,
indicando si la accin ha podido realizarse (por ejemplo, el mtodo next devolver
false si ya nos encontramos en la ltima posicin de la tabla). Este valor lo
almacenamos en la variable PosicionCorrecta (lnea 11) y lo utilizamos (lnea 47)
para actualizar la propiedad global Posicion con la nueva situacin del cursor (lnea
48) o con la posicin original del cursor (lnea 54), adems de proporcionar los datos
hallados (lneas 49 a 52) o una indicacin de que la operacin fue fallida (lneas 55 a
58).
Los mtodos Posicion (lnea 74) y DameDatos (lnea 78) proporcionan la
informacin que se consigue tras un posicionamiento (fallido o no).
JESS BOBADILLA SANCHO 157

1 import java.sql.*;
2
3 public class ObPosicionamiento {
4
5 private ObRegistro DatosPersona;
6 private int Posicion;
7
8 ObPosicionamiento(String Accion, int Posicion) {
9 int IDAccion,Edad;
10 String DNI,Nombre,Apellido;
11 boolean PosicionCorrecta=false;
12
13 try{
14 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
15 String BaseDeDatos = "jdbc:odbc:NombreLogico";
16 Connection Conexion =
17 DriverManager.getConnection(BaseDeDatos);
18 Statement SentenciaSQL = Conexion.createStatement(
19 ResultSet.TYPE_SCROLL_INSENSITIVE,
20 ResultSet.CONCUR_UPDATABLE);
21 ResultSet Personas = SentenciaSQL.executeQuery("SELECT
22 * FROM DatosPersonales");
23
24 Personas.absolute(Posicion);
25
26 IDAccion = Integer.parseInt(Accion);
27 switch (IDAccion) {
28 case 0: //
29 PosicionCorrecta = Personas.last();
30 break;
31 case 1:
32 PosicionCorrecta = Personas.first();
33 break;
34 case 2:
35 PosicionCorrecta = Personas.relative(-5);
36 break;
37 case 3:
38 PosicionCorrecta = Personas.previous();
39 break;
40 case 4:
41 PosicionCorrecta = Personas.next();
42 break;
43 case 5:
44 PosicionCorrecta = Personas.relative(+5);
45 break;
46 }
47 if (PosicionCorrecta) {
48 this.Posicion = Personas.getRow();

158 JESS BOBADILLA SANCHO
49 DNI = Personas.getString("DNI");
50 Nombre = Personas.getString("Nombre");
51 Apellido = Personas.getString("Apellido");
52 Edad = Personas.getInt("Edad");
53 } else {
54 this.Posicion = Posicion;
55 DNI = "----";
56 Nombre = "----";
57 Apellido = "----";
58 Edad = 0;
59 }
60 DatosPersona = new ObRegistro(DNI,Nombre,Apellido,Edad);
61
62 Personas.close();
63 Conexion.close();
64 SentenciaSQL.close();
65 }
66 catch (ClassNotFoundException e) {
67 System.out.println("Clase no encontrada");
68 }
69 catch (SQLException e) {
70 System.out.println(e);
71 }
72 }
73
74 public int Posicion() {
75 return Posicion;
76 }
77
78 public ObRegistro DameDatos() {
79 return DatosPersona;
80 }
81
82 }


7.7.9 Interfaz grfico de usuario (GUI)
Las clases que hemos desarrollado nos pueden servir para disear diferentes
aplicaciones de acceso a la tabla DatosPersonales. Como ejemplo de aplicacin que
hace uso de las mismas, se proporciona la clase GUIAccesoBD, que permite a un
usuario realizar consultas, inserciones, borrados, modificaciones y recorridos en
nuestra base de datos.
JESS BOBADILLA SANCHO 159

La estructura interna de la clase es la siguiente:

import java.awt.*;
import java.awt.event.*;

public class GUIAccesoBD {
// Propiedades privadas

GUIAccesoBD() {
// Definicion del interfaz grafico de usuario
// Establecimiento de los Listeners
}

private class ConsultarDatos implements ActionListener {
// Utiliza el objeto ObConsulta
}

private class InsertarDatos implements ActionListener {
// Utiliza el objeto ObInserccion
}

private class ModificarDatos implements ActionListener {
// Utiliza el objeto ObModificacion
}

private class BorrarDatos implements ActionListener {
// Utiliza el objeto ObBorrado
}

private class ListarDatos implements ActionListener {
// Utiliza el objeto ObListado
}

private class Controles implements ActionListener {
// Utiliza el objeto ObPosicionamiento
}
}
Vamos a analizar por separado cada uno de los elementos de la clase
GUIAccesoBD:


160 JESS BOBADILLA SANCHO
7.7.9.1 Constructor GUIAccesoBD
El constructor de esta clase se encarga de definir todo el interfaz grfico de
usuario que utiliza la aplicacin. El resultado es el siguiente:




En la siguiente porcin de cdigo se muestran las propiedades de la clase
(lneas 1 a 8) y el contenido del constructor (lnea 10). A partir de la lnea 84 se
aaden los ActionListeners, que responden a las pulsaciones del usuario en los
botones del GUI.
El mtodo DamePanel (lnea 99) proporciona el panel que contiene el GUI,
para que pueda ser insertado modularmente en aplicaciones con un interfaz grfico
de usuario ms completo.

1 private TextField CampoDNI;
2 private TextField CampoNombre;
3 private TextField CampoApellido;
4 private TextField CampoEdad;
5 private TextArea AreaDeListado;
6 private Panel MiPanel;
7
8 private int PosicionBuscada = 1;
9
10 GUIAccesoBD() {
11 MiPanel = new Panel(new GridLayout(1,2));
12 Panel PanelIzq = new Panel(new GridLayout(6,1));
13 Panel PanelDNI = new
14 Panel(new FlowLayout(FlowLayout.LEFT));
15 Panel PanelNombre = new
16 Panel(new FlowLayout(FlowLayout.LEFT));
17 Panel PanelApellido = new
18 Panel(new FlowLayout(FlowLayout.LEFT));
19 Panel PanelEdad = new
20 Panel(new FlowLayout(FlowLayout.LEFT));
21 Panel PanelAccion = new
22 Panel(new FlowLayout(FlowLayout.CENTER));
23 Panel PanelControles = new
JESS BOBADILLA SANCHO 161

24 Panel(new FlowLayout(FlowLayout.CENTER));
25
26 Label EtiquetaDNI = new Label("DNI");
27 Label EtiquetaNombre = new Label("Nombre");
28 Label EtiquetaApellido = new Label("Apellido");
29 Label EtiquetaEdad = new Label("Edad");
30
31 CampoDNI = new TextField(9);
32 CampoNombre = new TextField(15);
33 CampoApellido = new TextField(30);
34 CampoEdad = new TextField(3);
35
36 AreaDeListado = new TextArea();
37
38 Button BotonConsultar = new Button("Consultar");
39 Button BotonInsertar = new Button("Insertar");
40 Button BotonModificar = new Button("Modificar");
41 Button BotonBorrar = new Button("Borrar");
42 Button BotonListar = new Button("Listar");
43
44 Button BotonPrimero = new Button("|<");
45 BotonPrimero.setName("1");
46 Button BotonMenosCinco = new Button("--");
47 BotonMenosCinco.setName("2");
48 Button BotonAnterior = new Button("-");
49 BotonAnterior.setName("3");
50 Button BotonSiguiente = new Button("+");
51 BotonSiguiente.setName("4");
52 Button BotonMasCinco = new Button("++");
53 BotonMasCinco.setName("5");
54 Button BotonUltimo = new Button(">|");
55 BotonUltimo.setName("0");
56
57 PanelIzq .add(PanelDNI);
58 PanelIzq .add(PanelNombre);
59 PanelIzq .add(PanelApellido);
60 PanelIzq .add(PanelEdad);
61 PanelIzq .add(PanelAccion);
62 PanelIzq .add(PanelControles);
63 MiPanel.add(PanelIzq);
64 MiPanel.add(AreaDeListado);
65
66 PanelDNI.add (EtiquetaDNI); PanelDNI.add(CampoDNI);
67 PanelNombre.add (EtiquetaNombre);
68 PanelNombre.add(CampoNombre);
69 PanelApellido.add (EtiquetaApellido);
70 PanelApellido.add(CampoApellido);
71 PanelEdad.add (EtiquetaEdad); PanelEdad.add(CampoEdad);

162 JESS BOBADILLA SANCHO
72 PanelAccion.add(BotonConsultar);
73 PanelAccion.add(BotonInsertar);
74 PanelAccion.add(BotonModificar);
75 PanelAccion.add(BotonBorrar);
76 PanelAccion.add(BotonListar);
77 PanelControles.add(BotonPrimero);
78 PanelControles.add(BotonMenosCinco);
79 PanelControles.add(BotonAnterior);
80 PanelControles.add(BotonSiguiente);
81 PanelControles.add(BotonMasCinco);
82 PanelControles.add(BotonUltimo);
83
84 BotonConsultar.addActionListener(new ConsultarDatos());
85 BotonInsertar.addActionListener(new InsertarDatos());
86 BotonModificar.addActionListener(new ModificarDatos());
87 BotonBorrar.addActionListener(new BorrarDatos());
88 BotonListar.addActionListener(new ListarDatos());
89
90 BotonPrimero.addActionListener(new Controles());
91 BotonMenosCinco.addActionListener(new Controles());
92 BotonAnterior.addActionListener(new Controles());
93 BotonSiguiente.addActionListener(new Controles());
94 BotonMasCinco.addActionListener(new Controles());
95 BotonUltimo.addActionListener(new Controles());
96 }
97
98
99 public Panel DamePanel() {
100 return MiPanel;
101 }

7.7.9.2 Listener ConsultarDatos
El mtodo actionPerformed de la clase ConsultarDatos se encarga de
obtener los datos de una persona que se identifica a travs de su DNI. En las lneas
104 y 105 se crea un objeto de tipo ObConsulta, pasndole el DNI proporcionado
por el usuario.
Utilizamos el mtodo PosicionEncontrada, perteneciente a la clase
ObConsulta (lneas 106 y 107). Si se ha encontrado el registro (lnea 109),
obtenemos sus datos (lneas 110 y 111) y los mostramos en los campos del GUI
(lneas 112 a 114); si no se ha encontrado el registro, preparamos unos contenidos
que muestran esta situacin (lneas 116 a 118).

JESS BOBADILLA SANCHO 163

102 private class ConsultarDatos implements ActionListener {
103 public void actionPerformed(ActionEvent Evento) {
104 ObConsulta InstanciaConsulta = new
105 ObConsulta(CampoDNI.getText());
106 PosicionBuscada =
107 InstanciaConsulta.PosicionEncontrada();
108
109 if (PosicionBuscada!=0) {
110 ObRegistro InstanciaFila =
111 InstanciaConsulta.DameDatos();
112 CampoDNI.setText(InstanciaFila.DameDNI());
113 CampoNombre.setText(InstanciaFila.DameNombre());
114 CampoApellido.setText(InstanciaFila.DameApellido());
CampoEdad.setText(String.
valueOf(InstanciaFila.DameEdad()));
115 } else {
116 CampoNombre.setText("------");
117 CampoApellido.setText("------");
118 CampoEdad.setText("---");
119 }
120 }
121 }






7.7.9.3 Listener InsertarDatos
Para insertar un registro, en primer lugar creamos un objeto de tipo
ObRegistro con los datos proporcionados por el usuario (lneas 124 y 125);
posteriormente se crea una instancia del objeto ObInserccion, pasndole como
argumento el registro de tipo ObRegisto (lneas 127 y 128).
Despus de la insercin vaciamos los campos del GUI, con la intencin de
facilitar al usuario la introduccin de nuevos datos (lneas 129 y 130).


164 JESS BOBADILLA SANCHO
122 private class InsertarDatos implements ActionListener {
123 public void actionPerformed(ActionEvent Evento) {
124 ObRegistro InstanciaFila = new
ObRegistro(CampoDNI.getText(),CampoNombre.getText(),
125 CampoApellido.getText(),
Integer.parseInt(CampoEdad.getText()));
126
127 ObInserccion InstanciaInserccion = new
128 ObInserccion(InstanciaFila);
129 CampoDNI.setText(""); CampoNombre.setText("");
130 CampoApellido.setText(""); CampoEdad.setText("");
131 PosicionBuscada=1;
132 }
133 }






7.7.9.4 Listener ModificarDatos
La modificacin de datos comienza con una consulta (lneas 136 a 139),
proporcionando el DNI; despus preguntamos si se ha encontrado el registro (lnea
141). En caso afirmativo, se crea un registro con los nuevos datos (lneas 142 a 144)
y, posteriormente, se realiza la modificacin empleando este registro como
argumento (lneas 146 y 147).

134 private class ModificarDatos implements ActionListener {
135 public void actionPerformed(ActionEvent Evento) {
136 ObConsulta InstanciaConsulta = new
137 ObConsulta(CampoDNI.getText());
138 PosicionBuscada =
139 InstanciaConsulta.PosicionEncontrada();
140
141 if (PosicionBuscada!=0) {
142 ObRegistro InstanciaFila = new
143 ObRegistro(CampoDNI.getText(),
144 CampoNombre.getText(), CampoApellido.getText(),
JESS BOBADILLA SANCHO 165

Integer.parseInt(CampoEdad.getText()));
145
146 ObModificacion InstanciaModificacion = new
147 ObModificacion(PosicionBuscada, InstanciaFila);
148 CampoDNI.setText(""); CampoNombre.setText("");
149 CampoApellido.setText(""); CampoEdad.setText("");
150 } else {
151 CampoNombre.setText("------");
152 CampoApellido.setText("------");
153 CampoEdad.setText("---");
154 }
155 }
156 }





7.7.9.5 Listener BorrarDatos
La clase BorrarDatos es muy similar, en programacin, a la clase
ModificarDatos. En ambas se realiza primero una consulta (lneas 159 y 160), y tras
asegurarse de que hemos encontrado el registro a borrar (lneas 161 a 164), se crea
una instancia de la clase adecuada; en este caso ObBorrado (lneas 165 y 166).

157 private class BorrarDatos implements ActionListener {
158 public void actionPerformed(ActionEvent Evento) {
159 ObConsulta InstanciaConsulta = new
160 ObConsulta(CampoDNI.getText());
161 PosicionBuscada =
162 InstanciaConsulta.PosicionEncontrada();
163
164 if (PosicionBuscada!=0) {
165 ObBorrado InstanciaBorrado = new
166 ObBorrado(PosicionBuscada);
167 CampoDNI.setText(""); CampoNombre.setText("");
168 CampoApellido.setText(""); CampoEdad.setText("");
169 } else {
170 CampoNombre.setText("------");

166 JESS BOBADILLA SANCHO
171 CampoApellido.setText("------");
172 CampoEdad.setText("---");
173 }
174 }
175 }





7.7.9.6 Listener ListarDatos
La clase ListarDatos resulta especialmente simple: es suficiente crear una
instancia del objeto ObListado, pasndole como argumento el rea de texto donde se
desea situar el listado de los registros.

176 private class ListarDatos implements ActionListener {
177 public void actionPerformed(ActionEvent Evento) {
178 ObListado InstanciaListado = new
179 ObListado(AreaDeListado);
180 PosicionBuscada = 1;
181 }
182 }
183

7.7.9.7 Listener Controles
Cuando se ejecuta el nico mtodo actionPerformed del interfaz
ActionListener en la clase controles, lo primero que hay que hacer es determinar cul
ha sido el botn que ha generado el evento (lnea 186), obteniendo posteriormente su
nombre (lnea 187). En las lneas 45 a 55 se han establecido los nombres: 0, 1,
2, ... , 5. Despus se crea la instancia del objeto ObPosicionamiento, pasando
como argumentos: la accin deseada y la posicin actual en la tabla (lneas 188 y
189).
JESS BOBADILLA SANCHO 167

Por ltimo se obtienen los datos de la nueva posicin y, con ellos, se crea
un objeto de tipo ObRegistro (lneas 191 y 192), actualizando los campos del GUI
(lneas 193 a 197) y la posicin del cursor que mantenemos en la aplicacin (lnea
198).

184 private class Controles implements ActionListener {
185 public void actionPerformed(ActionEvent Evento) {
186 Button Pulsado = (Button) Evento.getSource();
187 String Identificador = Pulsado.getName();
188 ObPosicionamiento InstanciaPosicionamiento = new
189 ObPosicionamiento(Identificador,PosicionBuscada);
190
191 ObRegistro InstanciaFila =
192 InstanciaPosicionamiento.DameDatos();
193 CampoDNI.setText(InstanciaFila.DameDNI());
194 CampoNombre.setText(InstanciaFila.DameNombre());
195 CampoApellido.setText(InstanciaFila.DameApellido());
196 CampoEdad.setText(String.valueOf(
197 InstanciaFila.DameEdad()));
198 PosicionBuscada=InstanciaPosicionamiento.Posicion();
199 }
200 }



7.8 OBTENCIN DE METADATOS
Adems de poder acceder a los datos, tenemos la posibilidad de conocer
informacin general de las bases de datos y de la estructura de las tablas. La
informacin general la proporciona el interfaz DataBaseMetaData, mientras que la
informacin relativa a los tipos y propiedades de las columnas en un ResultSet la
conseguimos haciendo uso del interfaz ResultSetMetaData.
Los metadatos que se utilizan ms habitualmente son los que podemos
conseguir utilizando el interfaz ResultSetMetaData. Una vez que disponemos de un
objeto de tipo ResultSet, podemos definir una instancia de la clase
ResultSetMetaData, utilizando el mtodo getMetaData perteneciente al interfaz
ResultSet; en las lneas 14 y 15 del siguiente ejemplo se utiliza este mecanismo.
Entre la informacin de mayor inters que podemos obtener a travs de un
objeto de tipo ResultSetMetaData, se encuentra:



168 JESS BOBADILLA SANCHO
Informacin Mtodo
Nmero de campos int getColumnCount()
Tamao mximo del campo int getColumnDisplaySize(int Columna)
Nombre de un campo String getColumnName(int Columna)
Tipo SQL de un campo int getColumnType(int Columna)
Denominacin del tipo de un campo String getColumnTypeName(int Columna)
Nmero de dgitos decimales int getPrecision(int Columna)
Indica si el campo puede tomar el valor null int isNullable(int Columna)
Indica si el campo no puede ser escrito boolean isReadOnly(int Columna)
Indica si el campo puede ser usado en una
clusula where
boolean isSearchable(int Columna)
Indica si se puede realizar una escritura en el
campo
boolean isWritable(int Columna)

La clase MetaDatos (lnea 3) hace uso del interfaz ResultSetMetaData. El
objeto DatosInternos se obtiene aplicando el mtodo getMetaData al objeto
Personas, de tipo ResultSet (lneas 12 a 15).
A travs de DatosInternos podemos conocer el nmero de campos del
ResultSet, empleando el mtodo getColumnCount (lnea 16).
El bucle de la lnea 18 nos sirve para recorrer todos los campos de la tabla
DatosPersonales, obteniendo el nombre (getColumnName), tipo
(getColumnTypeName) y tamao mximo (getColumnDisplaySize) de cada uno de
ellos (lneas 20 a 24).

1 import java.sql.*;
2
3 public class MetaDatos {
4
5 public static void main(String[] args){
6 try{
7 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
8 String BaseDeDatos = "jdbc:odbc:NombreLogico";
9 Connection Conexion =
10 DriverManager.getConnection(BaseDeDatos);
11 Statement SentenciaSQL = Conexion.createStatement();
12 ResultSet Personas = SentenciaSQL.
13 executeQuery("SELECT * FROM DatosPersonales");
14 ResultSetMetaData DatosInternos =
15 Personas.getMetaData();
16 int NumeroDeColumnas= DatosInternos.getColumnCount();
17
18 for (int Columna=1;Columna<=NumeroDeColumnas;
19 Columna++) {
JESS BOBADILLA SANCHO 169

20 String Nombre=DatosInternos.getColumnName(Columna);
21 String Tipo =
22 DatosInternos.getColumnTypeName(Columna);
23 int Tamanio =
24 DatosInternos.getColumnDisplaySize(Columna);
25 System.out.println(Nombre+", "+Tipo+", "+Tamanio);
26 }
27
28 Personas.close();
29 Conexion.close();
30 SentenciaSQL.close();
31 }
32 catch (ClassNotFoundException e) {
33 System.out.println("Clase no encontrada");
34 }
35 catch (SQLException e) {
36 System.out.println(e);
37 }
38 }
39
40 }






7.9 EJECUCIN DE SENTENCIAS SQL QUE NO
DEVUELVEN RESULTADOS
Todos los ejemplos de bases de datos que hemos empleado utilizan el
mtodo executeQuery para ejecutar la sentencia SQL: SELECT * FROM
DatosPersonales. El mtodo executeQuery devuelve un objeto de tipo ResultSet
que contiene el resultado de la sentencia SQL, pero ... Qu ocurre cuando la
sentencia SQL no devuelve ningn resultado? En este caso se levanta una excepcin
del tipo SQLException. En el siguiente grfico podemos observar el mensaje
obtenido al ejecutar, con el mtodo executeQuery, la sentencia Sentencia SQL:
DELETE FROM DatosPersonales WHERE Nombre=Luis.

170 JESS BOBADILLA SANCHO






Las sentencias INSERT, DELETE y UPDATE modifican el contenido de la
base de datos, pero no devuelven ningn resultado ResultSet. Para ejecutar estas
sentencias debemos emplear el mtodo executeUpdate, perteneciente al interfaz
Statement. La clase Borrado2, en las lneas 15 y 16, nos muestra la manera de
hacerlo.

1 import java.sql.*;
2
3 public class Borrado2 {
4
5 public static void main(String[] args){
6 try{
7 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
8 String BaseDeDatos = "jdbc:odbc:NombreLogico";
9 Connection Conexion =
10 DriverManager.getConnection(BaseDeDatos);
11 Statement SentenciaSQL = Conexion.createStatement(
12 ResultSet.TYPE_SCROLL_INSENSITIVE,
13 ResultSet.CONCUR_UPDATABLE);
14
15 int Borrados = SentenciaSQL.executeUpdate("DELETE FROM
16 DatosPersonales WHERE Nombre='Luis'");
17
18 System.out.println(Borrados+" registros borrados");
19 Conexion.close();
20 SentenciaSQL.close();
21 }
22 catch (ClassNotFoundException e) {
23 System.out.println("Clase no encontrada");
24 }
25 catch (SQLException e) {
26 System.out.println(e);
27 } } }
JESS BOBADILLA SANCHO 171






En definitiva, cuando las sentencias SQL devuelven resultados, utilizamos el
mtodo executeQuery; cuando no devuelven resultados empleamos el mtodo
executeUpdate. En el siguiente ejemplo, SQLInteractivo, hacemos uso de ambos
mtodos del interfaz Statement; si la sentencia SQL es de alguno de los tipos:
UPDATE, DELETE o INSERT (lneas 15 a 17) utilizamos el mtodo executeUpdate
(lneas 18 y 19). En los dems casos usamos el mtodo executeQuery (lneas 23 y
24).
En el ejemplo, la sentencia SQL se proporciona como primer argumento
(args[0]) en la ejecucin del programa. Cuando se obtiene un resultado, se imprime
un listado de los registros (lneas 25 a 32). Tras el cdigo, se muestra el
funcionamiento del programa al introducirle diversas sentencias SQL de tipo
SELECT, UPDATE y DELETE.

1 import java.sql.*;
2
3 public class SQLInteractivo {
4
5 public static void main(String[] args){
6 String DNI,Nombre,Apellido; int Edad;
7 try{
8 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
9 String BaseDeDatos = "jdbc:odbc:NombreLogico";
10 Connection Conexion =
11 DriverManager.getConnection(BaseDeDatos);
12 Statement SentenciaSQL = Conexion.createStatement(
13 ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
14
15 if (args[0].startsWith("UPDATE")||
16 args[0].startsWith("DELETE")||
17 args[0].startsWith("INSERT")) {
18 int ElementosVariados =
19 SentenciaSQL.executeUpdate(args[0]);
20 System.out.println(ElementosVariados+" elementos han

172 JESS BOBADILLA SANCHO
21 sido actualizados, insertados o borrados");
22 } else {
23 ResultSet Personas =
24 SentenciaSQL.executeQuery(args[0]);
25 while (Personas.next()) {
26 DNI = Personas.getString("DNI");
27 Nombre = Personas.getString("Nombre");
28 Apellido = Personas.getString("Apellido");
29 Edad = Personas.getInt("Edad");
30 System.out.println(Nombre+" "+Apellido+",
31 "+Edad+", "+DNI);
32 }
33 Personas.close();
34 }
35 Conexion.close();
36 SentenciaSQL.close();
37 }
38 catch (ClassNotFoundException e) {
39 System.out.println("Clase no encontrada");
40 }
41 catch (SQLException e) {
42 System.out.println(e);
43 }
44 }
45
46 }

También podría gustarte