Programación Java Deitel (PDF)
Document Details
Uploaded by Deleted User
Deitel
Tags
Summary
Este libro proporciona una introducción a la programación en Java, centrándose en la interacción con bases de datos relacionales. Se explica el uso de JDBC para acceder a bases de datos y manipular sus datos. También se describen fundamentos de bases de datos relacionales y el lenguaje SQL.
Full Transcript
25 Acceso a bases de datos con Es un error capital especular antes de tener datos. —Arthur Conan Doyle JDBC Ahora ven, escríbelo en una tablilla, grábalo en un libro, y que dure hasta el último día, pa...
25 Acceso a bases de datos con Es un error capital especular antes de tener datos. —Arthur Conan Doyle JDBC Ahora ven, escríbelo en una tablilla, grábalo en un libro, y que dure hasta el último día, para testimonio. OBJETIVOS —La Santa Biblia, Isaías 30:8 En este capítulo aprenderá a: Primero consiga los Q Utilizar los conceptos acerca de las bases de datos relacionales. hechos, y después podrá Q Utilizar el Lenguaje de Consulta Estructurado (SQL) para distorsionarlos según le obtener y manipular los datos de una base de datos. parezca. Q Utilizar la API JDBC™ del paquete java.sql para acceder —Mark Twain a las bases de datos. Me gustan dos tipos de Q Utilizar la interfaz RowSet del paquete javax.sql para hombres: domésticos y manipular bases de datos. foráneos. Q Utilizar el descubrimiento de controladores de JDBC —Mae West automático de JDBC 4.0. Q Utilizar objetos PreparedStatement para crear instrucciones de SQL precompiladas con parámetros. Q Conocer cómo el procesamiento de transacciones hace que las aplicaciones de datos sea más robusto. 1042 Capítulo 25 Acceso a bases de datos con JDBC Pla n g e ne r a l 25.1 Introducción 25.2 Bases de datos relacionales 25.3 Generalidades acerca de las bases de datos relacionales: la base de datos libros 25.4 SQL 25.4.1 Consulta básica SELECT 25.4.2 La cláusula WHERE 25.4.3 La cláusula ORDER BY 25.4.4 Cómo fusionar datos de varias tablas: INNER JOIN 25.4.5 La instrucción INSERT 25.4.6 La instrucción UPDATE 25.4.7 La instrucción DELETE 25.5 Instrucciones para instalar MySQL y MySQL Connector/J 25.6 Instrucciones para establecer una cuenta de usuario de MySQL 25.7 Creación de la base de datos libros en MySQL 25.8 Manipulación de bases de datos con JDBC 25.8.1 Cómo conectarse y realizar consultas en una base de datos 25.8.2 Consultas en la base de datos libros 25.9 La interfaz RowSet 25.10 Java DB/Apache Derby 25.11 Objetos PreparedStatement 25.12 Procedimientos almacenados 25.13 Procesamiento de transacciones 25.14 Conclusión 25.15 Recursos Web y lecturas recomendadas Resumen | Terminología | Ejercicios de autoevaluación | Respuestas a los ejercicios de autoevaluación | Ejercicios 25.1 Introducción Una base de datos es una colección organizada de datos. Existen diversas estrategias para organizar datos y faci- litar el acceso y la manipulación. Un sistema de administración de bases de datos (DBMS) proporciona los mecanismos para almacenar, organizar, obtener y modificar datos para muchos usuarios. Los sistemas de admi- nistración de bases de datos permiten el acceso y almacenamiento de datos sin necesidad de preocuparse por su representación interna. En la actualidad, los sistemas de bases de datos más populares son las bases de datos relacionales, en donde los datos se almacenan sin considerar su estructura física (sección 25.2). Un lenguaje llamado SQL es el lenguaje estándar internacional que se utiliza casi universalmente con las bases de datos relacionales para realizar consultas (es decir, para solicitar información que satisfaga ciertos criterios) y para manipular datos. Algunos sistemas de administración de bases de datos relacionales (RDBMS) populares son Microsoft SQL Server, Oracle, Sybase, IBM DB2, Informix, PostgreSQL y MySQL. El JDK incluye ahora un RDBMS puro de Java, conocido como Java DB (la versión de Sun de Apache Derby). En este capítulo presentaremos ejemplos utilizando MySQL y Java DB.1 1. MySQL es uno de los sistemas de administración de bases de datos de código fuente abierto más populares de la actualidad. Al momento de escribir este libro todavía no soportaba JDBC 4, que forma parte de Java SE 6 (Mustang). Sin embargo, el sistema Java DB de Sun, que está basado en el sistema de administración de bases de datos de código fuente abierto Apache Derby y se incluye con el JDK 1.6.0 de Sun, sí ofrece soporte para JDSBC 4. En las secciones 25.8 a 25.10 utilizamos MySQL y JDBC 3, y en la sección 25.11 utilizamos Java DB y JDBC 4. 25.2 Bases de datos relacionales 1043 Los programas en Java se comunican con las bases de datos y manipulan sus datos utilizando la API JDBC™. Un controlador de JDBC permite a las aplicaciones de Java conectarse a una base de datos en un DBMS especí- fico, y nos permite manipular esa base de datos mediante la API JDBC. Observación de ingeniería de software 25.1 Al utilizar la API JDBC, los desarrolladores pueden modificar el DBMS subyacente sin necesidad de modificar el código de Java que accede a la base de datos. La mayoría de los sistemas de administración de bases de datos populares incluyen ahora controladores de JDBC. También hay muchos controladores de JDBC de terceros disponibles. En este capítulo presentaremos la tecnología JDBC y la emplearemos para manipular bases de datos de MySQL y Java DB. Las técnicas que demostraremos aquí también pueden usarse para manipular otras bases de datos que tengan controladores de JDBC. Consulte la documentación de su DBMS para determinar si incluye un controlador de JDBC. Incluso si su DBMS no viene con un controlador de JDBC, muchos distribuidores independientes proporcionan estos controladores para una amplia variedad de sistemas DBMS. Para obtener más información acerca de JDBC, visite la página: java.sun.com/javase/technologies/database/index.jsp Este sitio contiene información relacionada con JDBC, incluyendo las especificaciones de JDBC, preguntas frecuentes (FAQs) acerca de JDBC, un centro de recursos de aprendizaje y descargas de software para buscar controladores de JDBC para su DBMS, developers.sun.com/product/jdbc/drivers/ Este sitio proporciona un motor de búsqueda para ayudarlo a localizar los controladores apropiados para su DBMS. 25.2 Bases de datos relacionales Una base de datos relacional es una representación lógica de datos que permite acceder a éstos sin necesidad de considerar su estructura física. Una base de datos relacional almacena los datos en tablas. En la figura 25.1 se muestra una tabla de ejemplo que podría utilizarse en un sistema de personal. El nombre de la tabla es Empleado, y su principal propósito es almacenar los atributos de un empleado. Las tablas están compuestas de filas, y las filas, de columnas en las que se almacenan los valores. Esta tabla consiste de seis filas. La columna Numero de cada fila en esta tabla es su clave primaria: una columna (o grupo de columnas) en una tabla que tiene un valor único, el cual no puede duplicarse en las demás filas. Esto garantiza que cada fila pueda identificarse por su clave primaria. Algunos buenos ejemplos de columnas con clave primaria son un número de seguro social, un número de identifi- cación de empleado y un número de pieza en un sistema de inventario, ya que se garantiza que los valores en cada una de esas columnas serán únicos. Las filas de la figura 25.1 se muestran en orden, con base en la clave primaria. En este caso, las filas se muestran en orden ascendente; también podríamos utilizar el orden descendente. Número Nombre Departamento Salario Ubicación 23603 Jones 413 1100 New Jersey 24568 Kerwin 413 2000 New Jersey Fila 34589 Larson 642 1800 Los Angeles 35761 Myers 611 1400 Orlando 47132 Neumann 413 9000 New Jersey 78321 Stephens 611 8500 Orlando Clave primaria Columna Figura 25.1 | Datos de ejemplo de la tabla Empleado. 1044 Capítulo 25 Acceso a bases de datos con JDBC No se garantiza que las filas en las tablas se almacenen en un orden específico. Como lo demostraremos en un ejemplo más adelante, los programas pueden especificar criterios de ordenamiento al solicitar datos de una base de datos. Cada columna de la tabla representa un atributo de datos distinto. Las filas generalmente son únicas (por clave primaria) dentro de una tabla, pero los valores de columnas específicas pueden duplicarse entre filas. Por ejemplo, tres filas distintas en la columna Departamento de la tabla Empleado contienen el número 413. A menudo los distintos usuarios de una base de datos se interesan en datos diferentes, y en relaciones distintas entre esos datos. La mayoría de los usuarios requieren solamente de ciertos subconjuntos de las filas y columnas. Para obtener estos subconjuntos, utilizamos consultas para especificar cuáles datos se deben seleccionar de una tabla. Utilizamos SQL para definir consultas complejas que seleccionen datos de una tabla. Por ejemplo, podría- mos seleccionar datos de la tabla Empleado para crear un resultado que muestre en dónde se ubican los depar- tamentos, y presentar los datos ordenados en forma ascendente, por número de departamento. Este resultado se muestra en la figura 25.2. Hablaremos sobre las consultas de SQL en la sección 25.4. Departamento Ubicación 413 New Jersey 611 Orlando 642 Los Angeles Figura 25.2 | Resultado de seleccionar distintos datos de Departamento y Ubicacion de la tabla Empleado. 25.3 Generalidades acerca de las bases de datos relacionales: la base de datos libros Ahora veremos las generalidades sobre las bases de datos relacionales, y para ello emplearemos una base de datos llamada libros, misma que creamos para este capítulo. Antes de hablar sobre SQL, veremos una descripción general de las tablas de la base de datos libros. Utilizaremos esta base de datos para presentar varios conceptos de bases de datos, incluyendo el uso de SQL para obtener información de la base de datos y manipular los datos. Le proporcionaremos una secuencia de comandos (script) para crear la base de datos. En el directorio de ejemplos para este capítulo (en el CD que acompaña al libro) encontrará la secuencia de comandos. En la sección 25.5 le explicaremos cómo utilizar esta secuencia de comandos. La base de datos consiste de tres tablas: autores, isbnAutor y titulos. La tabla autores (descrita en la figura 25.3) consta de tres columnas que mantienen el número único de identificación de cada autor, su nombre de pila y apellido. La figura 25.4 contiene datos de ejemplo de la tabla autores de la base de datos libros. La tabla isbnAutor (descrita en la figura 25.5) consta de dos columnas que representan a cada ISBN y el correspondiente número de ID del autor. Esta tabla asocia a los autores con sus libros. Ambas columnas son cla- ves externas que representan la relación entre las tablas autores y titulos; una fila en la tabla autores puede estar asociada con muchas filas en la tabla titulos y viceversa. La figura 25.6 contiene datos de ejemplo de la tabla isbnAutor de la base de datos libros. [Nota: para ahorrar espacio, dividimos el contenido de esta tabla en Columna Descripción idAutor El número de identificación (ID) del autor en la base de datos. En la base de datos libros, esta columna de enteros se define como autoincrementada; para cada fila insertada en esta tabla, la base de datos incrementa automáticamente el valor de idAutor por 1 para asegurar que cada fila tenga un idAutor único. Esta columna representa la clave primaria de la tabla. nombrePila El nombre de pila del autor (una cadena). apellidoPaterno El apellido paterno del autor (una cadena). Figura 25.3 | La tabla autores de la base de datos libros. 25.3 Generalidades acerca de las bases de datos relacionales: la base de datos libros 1045 idAutor nombrePila apellidoPaterno 1 Harvey Deitel 2 Paul Deitel 3 Tem Nieto 4 Sean Santry Figura 25.4 | Datos de ejemplo de la tabla autores. Columna Descripción idAutor El número de identificación (ID) del autor, una clave externa para la tabla autores. isbn El ISBN para un libro, una clave externa para la tabla titulos. Figura 25.5 | La tabla isbnAutor de la base de datos libros. idAutor isbn idAutor isbn 1 0131869000 2 0131450913 2 0131869000 1 0131828274 1 0131483986 2 0131828274 2 0131483986 3 0131450913 1 0131450913 4 0131828274 Figura 25.6 | Datos de ejemplo de la tabla isbnAutor de libros. dos columnas, cada una de las cuales contiene las columnas idAutor y isbn.] La columna idAutor es una clave externa; una columna en esta tabla que coincide con la columna de la clave primaria en otra tabla (por ejemplo, idAutor en la tabla autores). Las claves externas se especifican al crear una tabla. La clave externa ayuda a man- tener la Regla de integridad referencial: todo valor de una clave externa debe aparecer como el valor de la clave primaria de otra tabla. Esto permite al DBMS determinar si el valor de idAutor para un libro específico es válido. Las claves externas también permiten seleccionar datos relacionados en varias tablas para fines analíticos; a esto se conoce como unir los datos. La tabla titulos descrita en la figura 25.7 consiste en cuatro columnas que representan el ISBN, el título, el número de edición y el año de copyright. La tabla está en la figura 25.8. Hay una relación de uno a varios entre una clave primaria y su correspondiente clave externa (por ejemplo, una editorial puede publicar muchos libros). Una clave externa puede aparecer varias veces en su propia tabla, pero sólo una vez (como clave primaria) en otra tabla. La figura 25.9 es un diagrama de relación de entidades (ER) para la base de datos libros. Este diagrama muestra las tablas en la base de datos, así como las relaciones entre ellas. El primer compartimiento en cada cuadro contiene el nombre de la tabla. Los nombres en cursiva son claves primarias. La clave primaria de una tabla identifica en forma única a cada fila. Cada fila debe tener un valor en la clave primaria, y éste debe ser único en la tabla. A esto se le conoce como Regla de integridad de entidades. Error común de programación 25.1 Si no se proporciona un valor para cada columna en una clave primaria, se quebranta la Regla de Integridad de Entidades y el DBMS reporta un error. 1046 Capítulo 25 Acceso a bases de datos con JDBC Columna Descripción isbn El número ISBN del libro (una cadena). La clave primaria de la tabla. ISBN son las siglas de “International Standard Book Number” (Número internacional normalizado para libros); un esquema de numeración utilizado por las editoriales en todo el mundo para dar a cada libro un número de identificación único. titulo Título del libro (una cadena). numeroEdicion Número de edición del libro (un entero). copyright Año de edición (copyright) del libro (una cadena). Figura 25.7 | La tabla titulos de la base de datos libros. isbn titulo numeroEdicion copyright 0131869000 Visual Basic How to Program 3 2006 0131525239 Visual C# How to Program 2 2006 0132222205 Java How to Program 7 2007 0131857576 C++ How to Program 5 2005 0132404168 C How to Program 5 2007 0131450913 Internet & World Wide Web 3 2004 How to Program Figura 25.8 | Datos de ejemplo para la tabla titulos de la base de datos libros. Autores ISBNAutor Titulos 1 1 IDAutor IDAutor ISBN NombrePila ISBN Titulo Apellido Paterno NumeroEdicion Copyright Figura 25.9 | Relaciones de las tablas en la base de datos libros. Error común de programación 25.2 Al proporcionar el mismo valor para la clave primaria en varias filas, el DBMS reporta un error. Las líneas que conectan las tablas en la figura 25.9 representan las relaciones entre las tablas. Considere la línea entre las tablas isbnAutor y autores. En el extremo de la línea que va a autores hay un 1, y en el extre- mo que va a isbnAutor hay un símbolo de infinito (∞), el cual indica una relación de uno a varios en la que cualquier autor de la tabla autores puede tener un número arbitrario de libros en la tabla isbnAutor. Observe que la línea de relación enlaza a la columna idAutor en la tabla autores (su clave primaria) con la columna idAutor en la tabla isbnAutor (es decir, su clave externa). La columna idAutor en la tabla isbnAutor es una clave externa. 25.4 SQL 1047 Error común de programación 25.3 Al proporcionar un valor de clave externa que no aparezca como valor de clave primaria en otra tabla, se quebranta la Regla de Integridad Referencial y el DBMS reporta un error. La línea entre las tablas titulos e isbnAutor muestra otra relación de uno a varios; un título puede ser escrito por cualquier número de autores. De hecho, el único propósito de la tabla isbnAutor es proporcionar una relación de varios a varios entre las tablas autores y titulos; un autor puede escribir cualquier número de libros y un libro puede tener cualquier número de autores. 25.4 SQL En esta sección veremos una descripción general acerca de SQL, en el contexto de nuestra base de datos libros. En los ejemplos posteriores y en los ejemplos de los capítulos 26 a 28, usted podrá utilizar las consultas de SQL que describimos aquí. Las palabras clave de SQL enlistadas en la figura 25.10 se describen en las siguientes subsecciones, dentro del contexto de consultas e instrucciones de SQL completas. Las demás palabras clave de SQL se encuentran más allá del alcance de este libro. Para aprender acerca de las otras palabras clave, consulte la guía de referencia de SQL que proporciona el distribuidor del RDBMS que usted utilice. [Nota: para obtener más información acerca de SQL, consulte los recursos Web en la sección 25.15 y las lecturas recomendadas que se enlistan al final de este capítulo]. Palabra clave de SQL Descripción SELECT Obtiene datos de una o más tablas. FROM Las tablas involucradas en la consulta. Se requiere para cada SELECT. WERE Los criterios de selección que determinan cuáles filas se van a recuperar, eliminar o actualizar. Es opcional en una consulta o instrucción de SQL. GROUP BY Criterios para agrupar filas. Es opcional en una consulta SELECT. ORDER BY Criterios para ordenar filas. Es opcional en una consulta SELECT. INNER JOIN Fusionar filas de varias tablas. INSERT Insertar filas en una tabla especificada. UPDATE Actualizar filas en una tabla especificada. DELETE Eliminar filas de una tabla especificada. Figura 25.10 | Palabras clave para consultas de SQL. 25.4.1 Consulta básica SELECT Veamos ahora varias consultas de SQL que extraen información de la base de datos libros. Una consulta de SQL “selecciona” filas y columnas de una o más tablas en una base de datos. Dichas selecciones se llevan a cabo mediante consultas con la palabra clave SELECT. La forma básica de una consulta SELECT es: SELECT * FROM nombreDeTabla en la consulta anterior, el asterisco (*) indica que deben obtenerse todas las columnas de la tabla nombreDeTabla. Por ejemplo, para obtener todos los datos en la tabla autores, podemos utilizar la siguiente consulta: SELECT * FROM autores La mayoría de los programas no requieren todos los datos en la tabla. Para obtener sólo ciertas columnas de una tabla, reemplace el asterisco (*) con una lista separada por comas de los nombres de las columnas. Por ejem- plo, para obtener solamente las columnas idAutor y apellidoPaterno para todas las filas en la tabla autores, utilice la siguiente consulta: 1048 Capítulo 25 Acceso a bases de datos con JDBC SELECT idAutor, apellidoPaterno FROM autores Esta consulta devuelve los datos que se muestran en la figura 25.11. idAutor apellidoPaterno 1 Deitel 2 Deitel 3 Nieto 4 Santry Figura 25.11 | Datos de ejemplo para idAutor y apellidoPaterno de la tabla autores. Observación de ingeniería de software 25.2 Para la mayoría de las consultas, no debe utilizarse el asterisco (*) para especificar nombres de columnas. En general, los programadores procesan los resultados sabiendo de antemano el orden de las columnas en el resultado; por ejem- plo, al seleccionar idAutor y apellidoPaterno de la tabla autores nos aseguramos que las columnas aparezcan en el resultado con idAutor como la primera columna y apellidoPaterno como la segunda. Generalmente los programas procesan las columnas de resultado especificando el número de columna en el resultado (empezando con el número 1 para la primera columna). Al seleccionar las columnas por nombre, también evitamos devolver columnas innecesarias y nos protegemos contra los cambios en el orden actual de las columnas en la(s) tabla(s). Error común de programación 25.4 Si un programador supone que las columnas siempre se devuelven en el mismo orden de una consulta que utiliza el asterisco (*), el programa podría procesar los resultados incorrectamente. Si cambia el orden de las columnas en la(s) tabla(s), o si se agregan más columnas posteriormente, el orden de las columnas en el resultado cambia de manera acorde. 25.4.2 La cláusula WHERE En la mayoría de los casos es necesario localizar, en una base de datos, filas que cumplan con ciertos criterios de selección. Sólo se seleccionan las filas que cumplan con los criterios de selección (formalmente llamados predi- cados). SQL utiliza la cláusula WHERE opcional en una consulta para especificar los criterios de selección para la misma. La forma básica de una consulta con criterios de selección es: SELECT nombreDeColumna1, nombreDeColumna2, … FROM nombreDeTabla WHERE criterios Por ejemplo, para seleccionar las columnas titulo, numeroEdicion y copyright de la tabla titulos para las cuales la fecha de copyright sea mayor que 2005, utilice la siguiente consulta: SELECT titulo, numeroEdicion, copyright FROM titulos WHERE copyright > '2005' En la figura 25.12 se muestra el resultado de la consulta anterior. Los criterios de la cláusula WHERE pueden contener los operadores , =, =, y LIKE. El operador LIKE se utiliza para relacionar patrones con los caracteres comodines porcentaje (%) y guión bajo (_). El relacionar patrones permite a SQL buscar cadenas que coincidan con un patrón dado. Un patrón que contenga un carácter de porcentaje (%) busca cadenas que tengan cero o más caracteres en la posición del carácter de porcentaje en el patrón. Por ejemplo, la siguiente consulta localiza las filas de todos los autores cuyo apellido paterno empiece con la letra D: SELECT idAutor, nombrePila, apellidoPaterno FROM autores WHERE apellidoPaterno LIKE 'D%' 25.4 SQL 1049 La consulta anterior selecciona las dos filas que se muestran en la figura 25.13, ya que dos de los cuatro autores en nuestra base de datos tienen un apellido paterno que empieza con la letra D (seguida de cero o más caracteres). El signo de % y el operador LIKE de la cláusula WHERE indican que puede aparecer cualquier número de caracteres después de la letra D en la columna apellidoPaterno. Observe que la cadena del patrón está encerrada entre caracteres de comilla sencilla. titulo numeroEdicion copyright Visual C# How to Program 2 2006 Visual Basic 2005 How to Program 3 2006 Java How to Program 7 2007 C How to Program 5 2005 Figura 25.12 | Ejemplos de títulos con fechas de copyright posteriores a 2005 de la tabla titulos. idAutor nombrePila apellidoPaterno 1 Harvey Deitel 2 Paul Deitel Figura 25.13 | Autores, cuyo apellido paterno empieza con D de la tabla autores. Tip de portabilidad 25.1 Consulte la documentación de su sistema de bases de datos para determinar si SQL es susceptible al uso de mayúsculas en su sistema, y para determinar la sintaxis de las palabras clave de SQL (por ejemplo, ¿deben estar completamen- te en mayúsculas, completamente en minúsculas o puede ser una combinación de ambas?). Tip de portabilidad 25.2 Lea cuidadosamente la documentación de su sistema de bases de datos para determinar si éste soporta el operador LIKE. El SQL que describimos es soportado por la mayoría de los RDBMS, pero siempre es buena idea comprobar las características de SQL que soporta su RDBMS. Un guión bajo ( _ ) en la cadena del patrón indica un carácter comodín individual en esa posición. Por ejemplo, la siguiente consulta localiza las filas de todos los autores cuyo apellido paterno empiece con cualquier carácter (lo que se especifica con _), seguido por la letra o, seguida por cualquier número de caracteres adicionales (lo que se especifica con %): SELECT idAutor, nombrePila, apellidoPaterno FROM autores WHERE apellidoPaterno LIKE '_o%' La consulta anterior produce la fila que se muestra en la figura 25.14, ya que sólo un autor en nuestra base de datos tiene un apellido paterno que contiene la letra o como su segunda letra. idAutor nombrePila apellidoPaterno 3 Andrew Goldberg Figura 25.14 | El único autor de la tabla autores cuyo apellido paterno contiene o como la segunda letra. 1050 Capítulo 25 Acceso a bases de datos con JDBC 25.4.3 La cláusula ORDER BY Las filas en el resultado de una consulta pueden ordenarse en forma ascendente o descendente, mediante el uso de la cláusula ORDER BY opcional. La forma básica de una consulta con una cláusula ORDER BY es: SELECT nombreDeColumna1, nombreDeColumna2 , … FROM nombreDeTabla ORDER BY columna ASC SELECT nombreDeColumna1, nombreDeColumna2 , … FROM nombreDeTabla ORDER BY columna DESC en donde ASC especifica el orden ascendente (de menor a mayor), DESC especifica el orden descendente (de mayor a menor) y columna especifica la columna en la cual se basa el ordenamiento. Por ejemplo, para obtener la lista de autores en orden ascendente por apellido paterno (figura 25.15), utilice la siguiente consulta: SELECT idAutor, nombrePila, apellidoPaterno FROM autores ORDER BY apellidoPaterno ASC Observe que el orden predeterminado es ascendente, por lo que ASC es opcional. Para obtener la misma lista de autores en orden descendente por apellido paterno (figura 25.16), utilice la siguiente consulta: SELECT idAutor, nombrePila, apellidoPaterno FROM autores ORDER BY apellidoPaterno DESC Pueden usarse varias columnas para ordenar mediante una cláusula ORDER BY, de la siguiente forma: ORDER BY columna1 tipoDeOrden, columna2 tipoDeOrden, … en donde tipoDeOrden puede ser ASC o DESC. Observe que el tipoDeOrden no tiene que ser idéntico para cada columna. La consulta: SELECT idAutor, nombrePila, apellidoPaterno FROM autores ORDER BY apellidoPaterno, nombrePila idAutor nombrePila apellidoPaterno 4 David Choffnes 1 Harvey Deitel 2 Paul Deitel 3 Andrew Goldberg Figura 25.15 | Datos de ejemplo de la tabla autores ordenados en forma ascendente por la columna apellidoPaterno. idAutor nombrePila apellidoPaterno 3 Andrew Goldberg 1 Harvey Deitel 2 Paul Deitel 4 David Choffnes Figura 25.16 | Datos de ejemplo de la tabla autores ordenados en forma descendente por la columna apellidoPaterno. 25.4 SQL 1051 ordena en forma ascendente todas las filas por apellido paterno, y después por nombre de pila. Si varias filas tienen el mismo valor de apellido paterno, se devuelven ordenadas por nombre de pila (figura 25.17). Las cláusulas WHERE y ORDER BY pueden combinarse en una consulta. Por ejemplo, la consulta: SELECT isbn, titulo, numeroEdicion, copyright, precio FROM titulos WHERE titulo LIKE '%How to Program' ORDER BY titulo ASC devuelve el isbn, titulo, numeroEdicion, copyright y precio de cada libro en la tabla titulos que tenga un titulo que termine con "How to Program" y los ordena en forma ascendente, por titulo. El resultado de la consulta se muestra en la figura 25.18. idAutor nombrePila apellidoPaterno 4 David Choffner 1 Harvey Deitel 2 Paul Deitel 3 Andrew Goldberg Figura 25.17 | Datos de ejemplo de autores de la tabla autores ordenados de manera ascendente, por las columnas apellidoPaterno y nombrePila. isbn titulo numeroEdicion copyright 0132404168 C How to Program 5 2007 0131857576 C++ How to Program 5 2005 0131450913 Internet & World Wide Web How to Program 3 2004 0132222205 Java How to Program 7 2007 0131869000 Visual Basic 2005 How to Program 3 2006 013152539 Visual C# How to Program 2 2006 Figura 25.18 | Ejemplos de libros de la tabla titulos cuyos títulos terminan con How to Program, y están ordenados en forma ascendente por medio de la columna titulo. 25.4.4 Cómo fusionar datos de varias tablas: INNER JOIN Los diseñadores de bases de datos a menudo dividen los datos en tablas separadas para asegurarse de no guardar información redundante. Por ejemplo, la base de datos libros tiene las tablas autores y titulos. Utilizamos una tabla isbnAutor para almacenar los datos de la relación entre los autores y sus correspondientes títulos. Si no separáramos esta información en tablas individuales, tendríamos que incluir la información del autor con cada entrada en la tabla titulos. Esto implicaría almacenar información duplicada sobre los autores en la base de datos, para quienes hayan escrito varios libros. A menudo es necesario fusionar datos de varias tablas en un solo resultado. Este proceso, que se le conoce como unir las tablas, se especifica mediante un operador INNER JOIN en la consulta. Un operador INNER JOIN fusiona las filas de dos tablas al relacionar los valores en columnas que sean comunes para las dos tablas. La forma básica de un INNER JOIN es: SELECT nombreDeColumna1, nombreDeColumna2, … FROM tabla1 1052 Capítulo 25 Acceso a bases de datos con JDBC INNER JOIN tabla2 ON tabla1.nombreDeColumna = tabla2.nombreDeColumna La cláusula ON de INNER JOIN especifica las columnas de cada tabla que se comparan para determinar cuáles filas se fusionan. Por ejemplo, la siguiente consulta produce una lista de autores acompañada por los ISBNs para los libros escritos por cada autor. SELECT nombrePila, apellidoPaterno, isbn FROM autores INNER JOIN isbnAutor ON autores.idAutor = isbnAutor.idAutor ORDER BY apellidoPaterno, nombrePila La consulta fusiona los datos de las columnas nombrePila y apellidoPaterno de la tabla autores con la columna isbn de la tabla isbnAutor, ordenando el resultado en forma ascendente por apellidoPaterno y nombrePila. Observe el uso de la sintaxis nombreDeTabla.nombreDeColumna en la cláusula ON. Esta sintaxis (a la que se le conoce como nombre calificado) especifica las columnas de cada tabla que deben compararse para unir las tablas. La sintaxis “nombreDeTabla.” es requerida si las columnas tienen el mismo nombre en ambas tablas. La misma sintaxis puede utilizarse en cualquier consulta para diferenciar entre columnas de tablas distintas que tengan el mismo nombre. En algunos sistemas pueden utilizarse nombres de tablas calificados con el nombre de la base de datos para realizar consultas entre varias bases de datos. Como siempre, la consulta puede contener una cláusula ORDER BY. En la figura 25.19 se muestra una parte de los resultados de la consulta anterior, ordena- dos por apellidoPaterno y nombrePila. [Nota: para ahorrar espacio dividimos el resultado de la consulta en dos columnas, cada una de las cuales contiene a las columnas nombrePila, apellidoPaterno e isbn]. Observación de ingeniería de software 25.3 Si una instrucción de SQL incluye columnas de varias tablas que tengan el mismo nombre, en la instrucción se debe anteponer a los nombres de esas columnas los nombres de sus tablas y el operador punto (por ejemplo, autores. idAutor). Error común de programación 25.5 Si no se califican los nombres para las columnas que tengan el mismo nombre en dos o más tablas se produce un error. nombrePila apellidoPaterno isbn nombrePila apellidoPaterno isbn David Choffnes 0131828274 Paul Deitel 0131525239 Harvey Deitel 0131525239 Paul Deitel 0132404168 Harvey Deitel 0132404168 Paul Deitel 0131869000 Harvey Deitel 0131869000 Paul Deitel 0132222205 Harvey Deitel 0132222205 Paul Deitel 0131450913 Harvey Deitel 0131450913 Paul Deitel 0131525239 Harvey Deitel 0131525239 Paul Deitel 0131857576 Harvey Deitel 0131857576 Paul Deitel 0131828274 Harvey Deitel 0131828274 Andrew Goldberg 0131450913 Figura 25.19 | Ejemplo de datos de autores e ISBNs para los libros que han escrito, en orden ascendente por apellidoPaterno y nombrePila. 25.4 SQL 1053 25.4.5 La instrucción INSERT La instrucción INSERT inserta una fila en una tabla. La forma básica de esta instrucción es: INSERT INTO nombreDeTabla ( nombreDeColumna1, nombreDeColumna2, …, nombreDeColumnaN ) VALUES ( valor1, valor2, …, valorN ) en donde nombreDeTabla es la tabla en la que se va a insertar la fila. El nombreDeTabla va seguido de una lista separada por comas de nombres de columnas entre paréntesis (esta lista no es requerida si la operación INSERT especifica un valor para cada columna de la tabla en el orden correcto). La lista de nombres de columnas va segui- da por la palabra clave VALUES de SQL, y una lista separada por comas de valores entre paréntesis. Los valores especificados aquí deben coincidir con las columnas especificadas después del nombre de la tabla, tanto en orden como en tipo (por ejemplo, si nombreDeColumna1 se supone que debe ser la columna nombrePila, entonces valor1 debe ser una cadena entre comillas sencillas que represente el nombre de pila). Siempre debemos enlistar explícitamente las columnas al insertar filas. Si el orden de las columnas cambia en la tabla, al utilizar solamente VALUES se puede provocar un error. La instrucción INSERT: INSERT INTO autores ( nombrePila, apellidoPaterno ) VALUES ( 'Alejandra', 'Villarreal' ) inserta una fila en la tabla autores. La instrucción indica que se proporcionan valores para las columnas nombre- Pila y apellidoPaterno. Los valores correspondientes son 'Alejandra' y 'Villarreal'. No especificamos un idAutor en este ejemplo, ya que idAutor es una columna autoincrementada en la tabla autores. Para cada fila que se agrega a esta tabla, MySQL asigna un valor de idAutor único que es el siguiente valor en la secuencia autoincrementada (por ejemplo: 1, 2, 3 y así sucesivamente). En este caso, Alejandra Villarreal recibiría el número 5 para idAutor. En la figura 25.20 se muestra la tabla autores después de la operación INSERT. [Nota: no todos los sistemas de administración de bases de datos soportan las columnas autoincrementadas. Consulte la documen- tación de su DBMS para encontrar alternativas a las columnas autoincrementadas]. idAutor nombrePila apellidoPaterno 1 Harvey Deitel 2 Paul Deitel 3 Andrew Goldberg 4 David Choffnes 5 Alejandra Villarreal Figura 25.20 | Datos de ejemplo de la tabla autores después de una operación INSERT. Error común de programación 25.6 Por lo general, es un error especificar un valor para una columna que se autoincrementa. Error común de programación 25.7 Las instrucciones de SQL utilizan el carácter de comilla sencilla (') como delimitador para las cadenas. Para espe- cificar una cadena que contenga una comilla sencilla (como O’Malley) en una instrucción de SQL, la cadena debe tener dos comillas sencillas en la posición en la que aparezca el carácter de comilla sencilla en la cadena (por ejemplo, 'O''Malley'). El primero de los dos caracteres de comilla sencilla actúa como carácter de escape para el segundo. Si no se utiliza el carácter de escape en una cadena que sea parte de una instrucción de SQL, se produce un error de sintaxis de SQL. 25.4.6 La instrucción UPDATE Una instrucción UPDATE modifica los datos en una tabla. La forma básica de la instrucción UPDATE es: 1054 Capítulo 25 Acceso a bases de datos con JDBC UPDATE nombreDeTabla SET nombreDeColumna1 = valor1, nombreDeColumna2 = valor2, …, nombreDeColumnaN = valorN WHERE criterios en donde nombreDeTabla es la tabla que se va a actualizar. El nombreDeTabla va seguido por la palabra clave SET y una lista separada por comas de los pares nombre/valor de las columnas, en el formato nombreDeColumna=valor. La cláusula WHERE opcional proporciona los criterios que determinan cuáles filas se van a actualizar. Aunque no es obligatoria, la cláusula WHERE se utiliza comúnmente, a menos que se vaya a realizar un cambio en todas las filas. La instrucción UPDATE: UPDATE autores SET apellidoPaterno = 'Garcia' WHERE apellidoPaterno = 'Villarreal' AND nombrePila = 'Alejandra' actualiza una fila en la tabla autores. La instrucción indica que apellidoPaterno recibirá el valor Garcia para la fila en la que apellidoPaterno sea igual a Villarreal y nombrePila sea igual a Alejandra. [Nota: si hay varias filas con el mismo nombre de pila “Alejandra” y el apellido paterno “Villarreal”, esta instrucción modificará a todas esas filas para que tengan el apellido paterno “Garcia”]. Si conocemos el idAutor desde antes de reali- zar la operación UPDATE (tal vez porque lo hayamos buscado con anterioridad), la cláusula WHERE se puede sim- plificar de la siguiente manera: WHERE idAutor = 5 En la figura 25.21 se muestra la tabla autores después de realizar la operación UPDATE. idAutor nombrePila apellidoPaterno 1 Harvey Deitel 2 Paul Deitel 3 Andrew Goldberg 4 David Choffnes 5 Alejandra Garcia Figura 25.21 | Datos de ejemplo de la tabla autores después de una operación UPDATE. 25.4.7 La instrucción DELETE Una instrucción DELETE de SQL elimina filas de una tabla. La forma básica de una instrucción DELETE es: DELETE FROM nombreDeTabla WHERE criterios en donde nombreDeTabla es la tabla de la que se van a eliminar filas. La cláusula WHERE opcional especifica los criterios utilizados para determinar cuáles filas eliminar. Si se omite esta cláusula, se eliminan todas las filas de la tabla. La instrucción DELETE: DELETE FROM autores WHERE apellidoPaterno = 'Garcia' AND nombrePila = 'Alejandra' elimina la fila de Alejandra Garcia en la tabla autores. Si conocemos el idAutor desde antes de realizar la ope- ración DELETE, la cláusula WHERE puede simplificarse de la siguiente manera: WHERE idAutor = 5 En la figura 25.22 se muestra la tabla autores después de realizar la operación DELETE. 25.5 Instrucciones para instalar MySQL y MySQL Connector/J 1055 idAutor nombrePila apellidoPaterno 1 Harvey Deitel 2 Paul Deitel 3 Andrew Goldberg 4 David Choffnes Figura 25.22 | Datos de ejemplo de la tabla autores después de una operación DELETE. 25.5 Instrucciones para instalar MySQL y MySQL Connector/J MySQL 5.0 Community Edition es un sistema de administración de bases de datos de código fuente abierto que se ejecuta en muchas plataformas, incluyendo Windows, Solaris, Linux y Macintosh. En el sitio www.mysql.com encontrará toda la información acerca de MySQL. Los ejemplos en las secciones 25.8 y 25.9 manipulan bases de datos de MySQL. Instalación de MySQL Para instalar MySQL Community Edition: 1. Para aprender acerca de los requerimientos de instalación para su plataforma, visite el sitio dev.mysql. com/doc/refman/5.0/en/general-installation-issues.html (para ver esta información en espa- ñol, visite el sitio dev.mysql.com/doc/refman/5.0/es/general-installation-issues.html). 2. Visite dev.mysql.com/downloads/mysql/5.0.html y descargue el instalador para su plataforma. Para los ejemplos de MySQL en este capítulo, sólo necesita el paquete Windows Essentials en Micro- soft Windows, o el paquete Standard en la mayoría de las otras plataformas. [Nota: para estas instruc- ciones, vamos a suponer que está utilizando Microsoft Windows. En el sitio dev.mysql.com/doc/ refman/5.0/en/installing.html (o dev.mysql.com/doc/refman/5.0/es/installing.html en español) encontrará las instrucciones completas de instalación para las otras plataformas]. 3. Haga doble clic en el archivo mysql-essential-5.0.27-win32.msi para iniciar el instalador. [Nota: el nombre de este archivo puede diferir, dependiendo de la versión actual de MySQL 5.0]. 4. Seleccione la opción Typical (Típica) en Setup Type (Tipo de instalación) y haga clic en Next > (Siguien- te). Después haga clic en Install (Instalar). Cuando termine la instalación, el programa le pedirá que configure una cuenta en MySQL.com. Si no desea hacerlo, seleccione Skip Sign-up (Omitir registro) y haga clic en Next > (Siguiente). Después de completar el pro- ceso de registro o de omitirlo, puede configurar el servidor de MySQL. Haga clic en Finish (Terminar) para iniciar el MySQL Server Instance Configuration Wizard (Asistente para la configuración de una instancia de MySQL Server). Para configurar el servidor: 1. Haga clic en Next > (Siguiente); después seleccione Standard Configuration (Configuración estándar) y haga clic en Next > otra vez. 2. Tiene la opción de instalar MySQL como servicio Windows, lo cual permite al servidor de MySQL empezar a ejecutarse automáticamente cada vez que su sistema se inicie. Para nuestros ejemplos esto no es necesario, por lo que puede desactivar la opción Install as a Windows Service (Instalar como servicio Windows), y después haga clic en la opción Include Bin Directory in Windows PATH (Incluir direc- torio Bin en la ruta PATH de Windows). Esto le permitirá usar los comandos de MySQL en el Símbolo del sistema de Windows. 3. Haga clic en Next > y después en Execute (Ejecutar) para llevar a cabo la configuración del servidor. 4. Haga clic en Finish (Terminar) para cerrar el asistente. 1056 Capítulo 25 Acceso a bases de datos con JDBC Instalación de MySQL Connector/J Para usar MySQL con JDBC, también necesita instalar MySQL Connector/J (la J representa a Java): un contro- lador de JDBC que permite a los programas usar JDBC para interactuar con MySQL. Puede descargar MySQL Connector/J de dev.mysql.com/downloads/connector/j/5.0.html La documentación para Connector/J se encuentra en dev.mysql.com/doc/connector/j/en/connector-j. html. Al momento de escribir este libro, la versión actual disponible en forma general de MySQL Connector/J es 5.0.4. Para instalar MySQL Connector/J: 1. Descargue el archivo mysql-connector-java-5.0.4.zip. 2. Abra mysql-connector-java-5.0.4.zip con un extractor de archivos, como WinZip (www.winzip. com). Extraiga su contenido en la unidad C:\. Esto creará un directorio llamado mysql-connector- java-5.0.4. La documentación para MySQL Connector/J está en el archivo connector-j.pdf en el subdirectorio docs de mysql-connector-java-5.0.4, o puede verla en línea, en el sitio dev.mysql. com/doc/connector/j/en/connector-j.html. 25.6 Instrucciones para establecer una cuenta de usuario de MySQL Para que los ejemplos de MySQL se ejecuten correctamente, necesita configurar una cuenta de usuario que per- mita a los usuarios crear, eliminar y modificar una base de datos. Una vez instalado MySQL, siga los pasos que se muestran a continuación para configurar una cuenta de usuario (en estos pasos asumimos que MySQL está instalado en su directorio predeterminado): 1. Abra una ventana de Símbolo del sistema e inicie el servidor de bases de datos, ejecutando el comando mysqld-nt.exe. Observe que este comando no tiene salida; simplemente inicia el servidor MySQL. No cierre esta ventana, de lo contrario el servidor dejará de ejecutarse. 2. A continuación, inicie el monitor de MySQL para que pueda configurar una cuenta de usuario; abra otra ventana de Símbolo del sistema y ejecute el comando mysql –h localhost –u root La opción –h indica el host (computadora) en el que se está ejecutando el servidor MySQL; en este caso, es su equipo local (localhost). La opción –u indica la cuenta de usuario que se utilizará para iniciar sesión en el servidor; root es la cuenta de usuario predeterminada que se crea durante la instalación, para que usted pueda configurar el servidor. Una vez que inicie sesión, aparecerá un indicador mysql> en el que podrá escribir comandos para interactuar con el servidor MySQL. 3. En el indicador mysql>, escriba USE mysql; para seleccionar la base de datos incrustada, llamada mysql, la cual almacena información relacionada con el servidor, como las cuentas de usuario y sus privilegios para interactuar con el servidor. Observe que cada comando debe terminar con punto y coma. Para confirmar el comando, MySQL genera el mensaje “Database changed.” (La base de datos cambió). 4. A continuación, agregue la cuenta de usuario jhtp7 a la base de datos incrustada mysql. Esta base de datos contiene una tabla llamada user, con columnas que representan el nombre del usuario, su con- traseña y varios privilegios. Para crear la cuenta de usuario jhtp7 con la contraseña jhtp7, ejecute los siguientes comandos desde el indicador mysql>: create user 'jhtp7'@'localhost' identified by 'jhtp7'; grant select, insert, update, delete, create, drop, references, execute on *.* to 'jhtp7’@’localhost'; 25.8 Manipulación de bases de datos con JDBC 1057 Esto crea el usuario jhtp7 con los privilegios necesarios para crear las bases de datos utilizadas en este capítulo, y para manipular esas bases de datos. Por último, 5. Escriba el comando exit; para terminar el monitor MySQL. 25.7 Creación de la base de datos libros en MySQL Para cada una de las bases de datos MySQL que veremos en este libro, proporcionamos una secuencia de coman- dos SQL en un archivo con la extensión.sql que configura la base de datos y sus tablas. Puede ejecutar estas secuencias de comandos en el monitor de MySQL. En el directorio de ejemplos de este capítulo, encontrará la secuencia de comandos SQL libros.sql para crear la base de datos libros. Para los siguientes pasos, vamos a suponer que el servidor MySQL (mysqld-nt.exe) sigue ejecutándose. Para ejecutar la secuencia de coman- dos libros.sql: 1. Abra una ventana de Símbolo del sistema y utilice el comando cd para cambiar al directorio en el que se encuentra la secuencia de comandos libros.sql. 2. Inicie el monitor de MySQL, escribiendo mysql –h localhost –u jhtp7 –p La opción –p hará que el monitor le pida la contraseña para el usuario jhtp7. Cuando ocurra esto, escriba la contraseña jhtp7. 3. Ejecute la secuencia de comandos, escribiendo source libros.sql; Esto creará un nuevo directorio llamado libros en el directorio data del servidor (en Windows, se encuentra en C:\Archivos de programa\MySQL\MySQL Server 5.0\data de manera predetermina- da). Este nuevo directorio contiene la base de datos libros. 4. Escriba el comando exit; para terminar el monitor de MySQL. Ahora está listo para continuar con el primer ejemplo de JDBC. 25.8 Manipulación de bases de datos con JDBC En esta sección presentaremos dos ejemplos. El primero le enseñará cómo conectarse a una base de datos y hacer consultas en ella. El segundo ejemplo le demostrará cómo mostrar en pantalla el resultado de la consulta. 25.8.1 Cómo conectarse y realizar consultas en una base de datos El ejemplo de la figura 25.23 realiza una consulta simple en la base de datos libros para obtener toda la tabla autores y mostrar los datos. El programa muestra cómo conectarse a la base de datos, hacer una consulta en la misma y procesar el resultado. En la siguiente discusión presentaremos los aspectos clave del programa rela- cionados con JDBC. [Nota: en las secciones 25.5 a 25.7 se muestra cómo iniciar el servidor MySQL, configurar una cuenta de usuario y crear la base de datos libros. Estos pasos deben realizarse antes de ejecutar el programa de la figura 25.23]. 1 // Fig. 25.23: MostrarAutores.java 2 // Muestra el contenido de la tabla autores. 3 import java.sql.Connection; 4 import java.sql.Statement; Figura 25.23 | Cómo mostrar el contenido de la tabla autores. (Parte 1 de 3). 1058 Capítulo 25 Acceso a bases de datos con JDBC 5 import java.sql.DriverManager; 6 import java.sql.ResultSet; 7 import java.sql.ResultSetMetaData; 8 import java.sql.SQLException; 9 10 public class MostrarAutores 11 { 12 // nombre del controlador de JDBC y URL de la base de datos 13 static final String CONTROLADOR = "com.mysql.jdbc.Driver"; 14 static final String URL_BASEDATOS = "jdbc:mysql://localhost/libros"; 15 16 // inicia la aplicación 17 public static void main( String args[] ) 18 { 19 Connection conexion = null; // maneja la conexión 20 Statement instruccion = null; // instrucción de consulta 21 ResultSet conjuntoResultados = null; // maneja los resultados 22 23 // se conecta a la base de datos libros y realiza una consulta 24 try 25 { 26 // carga la clase controlador 27 Class.forName( CONTROLADOR ); 28 29 // establece la conexión a la base de datos 30 conexion = 31 DriverManager.getConnection( URL_BASEDATOS, "jhtp7", "jhtp7" ); 32 33 // crea objeto Statement para consultar la base de datos 34 instruccion = conexion.createStatement(); 35 36 // consulta la base de datos 37 conjuntoResultados = instruccion.executeQuery( 38 "SELECT IDAutor, nombrePila, apellidoPaterno FROM autores" ); 39 40 // procesa los resultados de la consulta 41 ResultSetMetaData metaDatos = conjuntoResultados.getMetaData(); 42 int numeroDeColumnas = metaDatos.getColumnCount(); 43 System.out.println( "Tabla Autores de la base de datos Libros:\n" ); 44 45 for ( int i = 1; i ( modeloTabla ); 129 tablaResultados.setRowSorter( sorter ); 130 setSize( 500, 250 ); // establece el tamaño de la ventana 131 setVisible( true ); // muestra la ventana 132 133 // crea componente de escucha para botonFiltro 134 botonFiltro.addActionListener( 135 new ActionListener() 136 { 137 // pasa el texto del filtro al componente de escucha 138 public void actionPerformed( ActionEvent e ) 139 { 140 String texto = textoFiltro.getText(); 141 142 if ( texto.length() == 0 ) 143 sorter.setRowFilter( null ); 144 else 145 { 146 try 147 { 148 sorter.setRowFilter( 149 RowFilter.regexFilter( texto ) ); 150 } // fin de try 151 catch ( PatternSyntaxException pse ) Figura 25.28 | Visualización del contenido de la base de datos libros. (Parte 3 de 5). 25.8 Manipulación de bases de datos con JDBC 1071 152 { 153 JOptionPane.showMessageDialog( null, 154 "Patron de exp reg incorrecto", "Patron de exp reg incorrecto", 155 JOptionPane.ERROR_MESSAGE ); 156 } // fin de catch 157 } // fin de else 158 } // fin del método actionPerfomed 159 } // fin de la clase interna anónima 160 ); // fin de la llamada a addActionLister 161 } // fin de try 162 catch ( ClassNotFoundException noEncontroClase ) 163 { 164 JOptionPane.showMessageDialog( null, 165 "No se encontro controlador de base de datos", "No se encontro el controlador", 166 JOptionPane.ERROR_MESSAGE ); 167 168 System.exit( 1 ); // termina la aplicación 169 } // fin de catch 170 catch ( SQLException excepcionSql ) 171 { 172 JOptionPane.showMessageDialog( null, excepcionSql.getMessage(), 173 "Error en base de datos", JOptionPane.ERROR_MESSAGE ); 174 175 // verifica que esté cerrada la conexión a la base de datos 176 modeloTabla.desconectarDeBaseDatos(); 177 178 System.exit( 1 ); // termina la aplicación 179 } // fin de catch 180 181 // cierra la ventana cuando el usuario sale de la aplicación (se sobrescribe 182 // el valor predeterminado de HIDE_ON_CLOSE) 183 setDefaultCloseOperation( DISPOSE_ON_CLOSE ); 184 185 // verifica que esté cerrada la conexión a la base de datos cuando el usuario sale de la aplicación 186 addWindowListener( 187 188 new WindowAdapter() 189 { 190 // se desconecta de la base de datos y sale cuando se ha cerrado la ventana 191 public void windowClosed( WindowEvent evento ) 192 { 193 modeloTabla.desconectarDeBaseDatos(); 194 System.exit( 0 ); 195 } // fin del método windowClosed 196 } // fin de la clase interna WindowAdapter 197 ); // fin de la llamada a addWindowListener 198 } // fin del constructor de MostrarResultadosConsulta 199 200 // ejecuta la aplicación 201 public static void main( String args[] ) 202 { 203 new MostrarResultadosConsulta(); 204 } // fin de main 205 } // fin de la clase MostrarResultadosConsulta Figura 25.28 | Visualización del contenido de la base de datos libros. (Parte 4 de 5). 1072 Capítulo 25 Acceso a bases de datos con JDBC Figura 25.28 | Visualización del contenido de la base de datos libros. (Parte 5 de 5). En las líneas 86 a 125 se registra un manejador de eventos para el botonEnviar en el que el usuario hace clic para enviar una consulta a la base de datos. Cuando el usuario hace clic en el botón, el método actionPerformed (líneas 91 a 123) invoca al método establecerConsulta de la clase ResultSetTableModel para ejecutar la nue- va consulta. Si la consulta del usuario falla (por ejemplo, debido a un error de sintaxis en la entrada del usuario), en las líneas 108 y 109 se ejecuta la consulta predeterminada. Si la consulta predeterminada también falla, podría haber un error más grave, por lo que en la línea 118 se asegura que se cierre la conexión a la base de datos y en la línea 120 se sale del programa. Las capturas de pantalla de la figura 25.28 muestran los resultados de dos consul- tas. La primera captura de pantalla muestra la consulta predeterminada, en la que se recuperan todos los datos de la tabla autores de la base de datos libros. La segunda captura de pantalla muestra una consulta que selecciona el nombre de pila y el apellido paterno de cada autor en la tabla autores, y combina esa información con el título y número de edición de la tabla titulos. Pruebe a introducir sus propias consultas en el área de texto y haga clic en el botón Enviar consulta para enviar la consulta. A partir de Java SE 6, los objetos JTable ahora permiten a los usuarios ordenar filas en base a los datos en una columna específica. En las líneas 127 y 128 se utiliza la clase TableRowSorter (del paquete javax.swing. table) para crear un objeto que utilice nuestro objeto ResultSetTableModel para ordenar filas en el objeto JTable que muestre los resultados de la consulta. Cuando el usuario hace clic en el título de una columna 25.9 La interfaz RowSet 1073 específica del objeto JTable, el objeto TableRowSorter interactúa con el objeto TableModel subyacente para reordenar las filas, con base en los datos en esa columna. En la línea 129 se utiliza el método setRowSorter del método JTable para especificar el objeto TableRowSorter para tablaResultados. Otra de las nuevas características de los objetos JTable es la habilidad de ver subconjuntos de los datos del objeto TableModel subyacente. A esto se le conoce como filtrar los datos. En las líneas 134 a 160 se registra un manejador de eventos para el botonFiltro que el usuario oprime para filtrar los datos. En el método action- Performed (líneas 138 a 158), en la línea 140 se obtiene el texto de filtro. Si el usuario no especificó un texto de filtro, en la línea 143 se utiliza el método setRowFilter de JTable para eliminar cualquier filtro anterior, estableciendo el filtro en null. En caso contrario, en las líneas 148 y 149 se utiliza setRowFilter para especificar un objeto RowFilter (del paquete javax.swing) con base en la entrada del usuario. La clase RowFilter cuenta con varios métodos para crear filtros. El método static regexFilter recibe un objeto String que contiene un patrón de expresión regular como argumento, y un conjunto opcional de índices que especifican cuáles columnas se van a filtrar. Si no se especifican índices, entonces se busca en todas las columnas. En este ejemplo, el patrón de expresión regular es el texto que escribió el usuario. Una vez establecido el filtro, se actualizan los datos mostrados en el objeto JTable con base en el objeto TableModel filtrado. 25.9 La interfaz RowSet En los ejemplos anteriores, aprendido a realizar consultas en una base de datos al establecer en forma explícita una conexión (Connection) a la base de datos, preparar una instrucción (Statement) para consultar la base de datos y ejecutar la consulta. En esta sección demostraremos la interfaz RowSet, la cual configura la conexión a la base de datos y prepara instrucciones de consulta en forma automática. La interfaz RowSet proporciona varios métodos establecer (get) que nos permiten especificar las propiedades necesarias para establecer una conexión (como el URL de la base de datos, el nombre de usuario y la contraseña) y crear un objeto Statement (como una consulta). RowSet también cuenta con varios métodos obtener (get) para devolver estas propiedades. Hay dos tipos de objetos RowSet: conectados y desconectados. Un objeto RowSet conectado se conecta a la base de datos una sola vez, y permanece conectado hasta que termina la aplicación. Un objeto RowSet desco- nectado se conecta a la base de datos, ejecuta una consulta para obtener los datos de la base de datos y después cierra la conexión. Un programa puede cambiar los datos en un objeto RowSet desconectado, mientras éste se encuentre desconectado. Los datos modificados pueden actualizarse en la base de datos, después de que un objeto RowSet desconectado reestablece la conexión a la base de datos. El paquete javax.sql.rowset contiene dos subinterfaces de RowSet: JdbcRowSet y CachedRowSet. Jdbc- RowSet, un objeto RowSet conectado, actúa como una envoltura alrededor de un objeto ResultSet y nos per- mite desplazarnos a través de las filas en el objeto ResultSet, y también actualizarlas. Recuerde que, de manera predeterminada, un objeto ResultSet no es desplazable y es de sólo lectura; debemos establecer explícitamente la constante de tipo del conjunto de resultados a TYPE_SCROLL_INSENSITIVE y establecer la constante de con- currencia del conjunto de resultados CONCUR_UPDATABLE para hacer que un objeto ResultSet sea desplazable y pueda actualizarse. Un objeto JdbcRowSet es desplazable y puede actualizarse de manera predeterminada. CachedRowSet, un objeto RowSet desconectado, coloca los datos de un objeto ResultSet en caché de memoria y los desconecta de la base de datos. Al igual que un objeto JdbcRowSet, un objeto CachedRowSet es desplaza- ble y puede actualizarse de manera predeterminada. Un objeto CachedRowSet también es serializable, por lo que puede pasarse de una aplicación de Java a otra mediante una red, como Internet. Sin embargo, CachedRowSet tiene una limitación: la cantidad de datos que pueden almacenarse en memoria es limitada. El paquete javax. sql.rowset contiene otras tres subinterfaces de RowSet. Para obtener detalles de estas interfaces, visite java. sun.com/javase/6/docs/technotes/guides/jdbc/getstart/rowsetImpl.html. Tip de portabilidad 25.5 Un objeto RowSet puede proporcionar capacidad de desplazamiento a los controladores que no tienen soporte para objetos ResultSet desplazables. En la figura 25.29 se reimplementa el ejemplo de la figura 25.23, usando un objeto RowSet. En vez de establecer la conexión y crear un objeto Statement de manera explícita, en la figura 25.29 utilizamos un objeto JdbcRowSet para crear los objetos Connection y Statement de manera automática. 1074 Capítulo 25 Acceso a bases de datos con JDBC 1 // Fig. 25.29: PruebaJdbcRowSet.java 2 // Visualización del contenido de la tabla autores, mediante el uso de JdbcRowSet. 3 import java.sql.ResultSetMetaData; 4 import java.sql.SQLException; 5 import javax.sql.rowset.JdbcRowSet; 6 import com.sun.rowset.JdbcRowSetImpl; // implementación de JdbcRowSet de Sun 7 8 public class PruebaJdbcRowSet 9 { 10 // nombre del controlador de JDBC y URL de la base de datos 11 static final String CONTROLADOR = "com.mysql.jdbc.Driver"; 12 static final String URL_BASEDATOS = "jdbc:mysql://localhost/libros"; 13 static final String NOMBREUSUARIO = "jhtp7"; 14 static final String CONTRASENIA = "jhtp7"; 15 16 // el constructor se conecta a la base de datos, la consulta, procesa 17 // los resultados y los muestra en la ventana 18 public PruebaJdbcRowSet() 19 { 20 // se conecta a la base de datos libros y la consulta 21 try 22 { 23 Class.forName( CONTROLADOR ); 24 25 // especifica las propiedades del objeto JdbcRowSet 26 JdbcRowSet rowSet = new JdbcRowSetImpl(); 27 rowSet.setUrl( URL_BASEDATOS ); // establece URL de la base de datos 28 rowSet.setUsername( NOMBREUSUARIO ); // establece el nombre de usuario 29 rowSet.setPassword( CONTRASENIA ); // establece contraseña 30 rowSet.setCommand( "SELECT * FROM autores" ); // establece la consulta 31 rowSet.execute(); // ejecuta la consulta 32 33 // procesa los resultados de la consulta 34 ResultSetMetaData metaDatos = rowSet.getMetaData(); 35 int numeroDeColumnas = metaDatos.getColumnCount(); 36 System.out.println( "Tabla Autores de la base de datos Libros:\n" ); 37 38 // muestra el encabezado del objeto RowSet 39 for ( int i = 1; i , escriba connect 'jdbc:derby:LibretaDirecciones;create=true;user=jhtp7;password=jhtp7'; para crear la base de datos LibretaDirecciones en el directorio actual. Este comando también crea el usuario jhtp7 con la contraseña jhtp7 para acceder a la base de datos. 7. Para crear la tabla de la base de datos e insertar los datos de ejemplo, escriba run 'direccion.sql'; 8. Para terminar la herramienta de línea de comandos de Java DB, escriba exit; Ahora está listo para ejecutar la aplicación LibretaDirecciones en la sección 25.12. 25.11 Objetos PreparedStatement La interfaz PreparedStatement nos permite crear instrucciones SQL compiladas, que se ejecutan con más eficiencia que los objetos Statement. Las instrucciones PreparedStatement también pueden especificar pará- metros, lo cual las hace más flexibles que las instrucciones Statement. Los programas pueden ejecutar la misma 25.11 Objetos PreparedStatement 1077 consulta varias veces, con distintos valores para los parámetros. Por ejemplo, en la base de datos libros, tal vez sea conveniente localizar todos los libros para un autor con un apellido paterno y primer nombre específicos, y ejecutar esa consulta para varios autores. Con un objeto PreparedStatement, esa consulta se define de la siguien- te manera: PreparedStatement librosAutor = connection.prepareStatement( "SELECT apellidoPaterno, primerNombre, titulo " + "FROM autores INNER JOIN isbnAutor " + "ON autores.idAutor=isbnAutor.idAutor " + "INNER JOIN titulos " + "ON isbnAutor.isbn=titulos.isbn " + "WHERE apellidoPaterno = ? AND primerNombre = ?" ); Los dos signos de interrogación (?) en la última línea de la instrucción SQL anterior son receptáculos para valores que se pasarán como parte de la consulta en la base de datos. Antes de ejecutar una instrucción PreparedState- ment, el programa debe especificar los valores de los parámetros mediante el uso de los métodos establecer (set) de la interfaz PreparedStatement. Para la consulta anterior, ambos parámetros son cadenas que pueden establecerse con el método setString de PreparedStatement, como se muestra a continuación: librosAutor.setString( 1, "Deitel" ); librosAutor.setString( 2, "Paul" ); El primer argumento del método setString representa el número del parámetro que se va a establecer, y el segundo argumento es el valor de ese parámetro. Los números de los parámetros se cuentan a partir de 1, empezando con el primer signo de interrogación (?). Cuando el programa ejecuta la instrucción Prepared- Statement anterior con los valores de los parámetros que se muestran aquí, la instrucción SQL que se pasa a la base de datos es SELECT apellidoPaterno, primerNombre, titulo FROM autores INNER JOIN isbnAutor ON autores.idAutor=isbnAutor.idAutor INNER JOIN titulos ON isbnAutor.isbn=titulos.isbn WHERE apellidoPaterno = 'Deitel' AND primerNombre = 'Paul' El método setString escapa de manera automática los valores de los parámetros String según sea necesario. Por ejemplo, si el apellido paterno es O’Brien, la instrucción librosAutor.setString( 1, "O'Brien" ); escapa el carácter ' en O’Brien, sustituyéndolo con dos caracteres de comilla sencilla. Tip de rendimiento 25.2 Las instrucciones PreparedStatement son más eficientes que las instrucciones Statement al ejecutar instrucciones SQL varias veces, y con distintos valores para los parámetros. Tip para prevenir errores 25.1 Use las instrucciones PreparedStatement con parámetros para las consultas que reciban valores String como argumentos, para asegurar que los objetos String utilicen comillas de manera apropiada en la instrucción SQL. La interfaz PreparedStatement proporciona métodos establecer (set) para cada tipo de SQL soportado. Es importante utilizar el método establecer que sea apropiado para el tipo de SQL del parámetro en la base de datos; las excepciones SQLException ocurren cuando un programa trata de convertir el valor de un parámetro en un tipo incorrecto. Para una lista completa de los métodos establecer (set) de la interfaz PreparedStatement, consul- te la página Web java.sun.com/javase/6/docs/api/java/sql/PreparedStatement.html. 1078 Capítulo 25 Acceso a bases de datos con JDBC Aplicación “libreta de direcciones” que utiliza instrucciones PreparedStatement Ahora presentaremos una aplicación “libreta de direcciones” que nos permite explorar las entradas existentes, agregar nuevas entradas y buscar entradas con un apellido paterno específico. Nuestra base de datos LibretaDireccio- nes de JavaDB contiene una tabla Direcciones con las columnas idDireccion, primerNombre, apellido- Paterno, email y numeroTelefonico. La columna idDireccion se denomina columna de identidad. Ésta es la manera estándar de SQL para representar una columna autoincrementada. La secuencia de comandos SQL que proporcionamos para esta base de datos utiliza la palabra clave IDENTITY de SQL para marcar la columna idDi- reccion como una columna de identidad. Para obtener más información acerca de la palabra IDENTITY y crear bases de datos, consulte la Guía para el desarrollador de Java DB en developers.sun.com/prodtech/javadb/ reference/docs/10.2.1.6/devguide/index.html. Nuestra aplicación de libro de direcciones consiste en tres clases: Persona (figura 25.30), ConsultasPer- sona (figura 25.31) y MostrarLibretaDirecciones (figura 25.32). La clase Persona es una clase simple que representa a una persona en la libreta de direcciones. Esta clase contiene campos para el ID de dirección, primer nombre, apellido paterno, dirección de e-mail y número telefónico, así como métodos establecer y obtener para manipular esos campos. 1 // Fig. 25.30: Persona.java 2 // La clase Persona representa una entrada en una libreta de direcciones. 3 public class Persona 4 { 5 private int idDireccion; 6 private String primerNombre; 7 private String apellidoPaterno; 8 private String email; 9 private String numeroTelefonico; 10 11 // constructor sin argumentos 12 public Persona() 13 { 14 } // fin del constructor de Persona sin argumentos 15 16 // constructor 17 public Persona( int id, String nombre, String apellido, 18 String direccionEmail, String telefono ) 19 { 20 establecerIDDireccion( id ); 21 establecerPrimerNombre( nombre ); 22 establecerApellidoPaterno( apellido ); 23 establecerEmail( direccionEmail ); 24 establecerNumeroTelefonico( telefono ); 25 } // fin del constructor de Persona con cinco argumentos 26 27 // establece el objeto idDireccion 28 public void establecerIDDireccion( int id ) 29 { 30 idDireccion = id; 31 } // fin del método establecerIDDireccion 32 33 // devuelve el valor de idDireccion 34 public int obtenerIDDireccion() 35 { 36 return idDireccion; 37 } // fin del método obtenerIDDireccion 38 39 // establece el primerNombre 40 public void establecerPrimerNombre( String nombre ) Figura 25.30 | La clase Persona representa una entrada en un objeto LibretaDirecciones. (Parte 1 de 2). 25.11 Objetos PreparedStatement 1079 41 { 42 primerNombre = nombre; 43 } // fin del método establecerPrimerNombre 44 45 // devuelve el primer nombre 46 public String obtenerPrimerNombre() 47 { 48 return primerNombre; 49 } // fin del método obtenerPrimerNombre 50 51 // establece el apellidoPaterno 52 public void establecerApellidoPaterno( String apellido ) 53 { 54 apellidoPaterno = apellido; 55 } // fin del método establecerApellidoPaterno 56 57 // devuelve el apellido paterno 58 public String obtenerApellidoPaterno() 59 { 60 return apellidoPaterno; 61 } // fin del método obtenerApellidoPaterno 62 63 // establece la dirección de email 64 public void establecerEmail( String direccionEmail ) 65 { 66 email = direccionEmail; 67 } // fin del método establecerEmail 68 69 // devuelve la dirección de email 70 public String obtenerEmail() 71 { 72 return email; 73 } // fin del método obtenerEmail 74 75 // establece el número telefónico 76 public void establecerNumeroTelefonico( String telefono ) 77 { 78 numeroTelefonico = telefono; 79 } // fin del método establecerNumeroTelefonico 80 81 // devuelve el número telefónico 82 public String obtenerNumeroTelefonico() 83 { 84 return numeroTelefonico; 85 } // fin del método obtenerNumeroTelefonico 86 } // fin de la clase Persona Figura 25.30 | La clase Persona representa una entrada en un objeto LibretaDirecciones. (Parte 2 de 2). La clase ConsultasPersona La clase ConsultasPersona (figura 25.31) maneja la conexión a la base de datos de la aplicación libreta de di- recciones y crea las instrucciones PreparedStatement que utiliza la aplicación para interactuar con la base de datos. En las líneas 18 a 20 se declaran tres variables PreparedStatement. El constructor (líneas 23 a 49) se conecta con la base de datos en las líneas 27 y 28. Observe que no utilizamos Class.forName para cargar el controlador de la base de datos para Java DB, como hicimos en los ejemplos que utilizan MySQL en secciones anteriores de este capítulo. JDBC 4.0, que forma parte de Java SE 6, soporta el descubrimiento automático de controladores; ya no tenemos que cargar el controlador de la base de datos por adelantado. Al momento de escribir este libro, esta característica se encuentra en proceso de implementarse en MySQL. 1080 Capítulo 25 Acceso a bases de datos con JDBC 1 // Fig. 25.31: ConsultasPersona.java 2 // Instrucciones PreparedStatement utilizadas por la aplicación Libreta de direcciones 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.PreparedStatement; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.util.List; 9 import java.util.ArrayList; 10 11 public class ConsultasPersona 12 { 13 private static final String URL = "jdbc:derby:LibretaDirecciones"; 14 private static final String NOMBREUSUARIO = "jhtp7"; 15 private static final String CONTRASENIA = "jhtp7"; 16 17 private Connection conexion = null; // maneja la conexión 18 private PreparedStatement seleccionarTodasLasPersonas = null; 19 private PreparedStatement seleccionarPersonasPorApellido = null; 20 private PreparedStatement insertarNuevaPersona = null; 21 22 // constructor 23 public ConsultasPersona() 24 { 25 try 26 { 27 conexion = 28 DriverManager.getConnection( URL, NOMBREUSUARIO, CONTRASENIA ); 29 30 // crea una consulta que selecciona todas las entradas en la LibretaDirecciones 31 seleccionarTodasLasPersonas = 32 conexion.prepareStatement( "SELECT * FROM Direcciones" ); 33 34 // crea una consulta que selecciona las entradas con un apellido específico 35 seleccionarPersonasPorApellido = conexion.prepareStatement( 36 "SELECT * FROM Direcciones WHERE ApellidoPaterno = ?" ); 37 38 // crea instrucción insert para agregar una nueva entrada en la base de 39 datos 39 insertarNuevaPersona = conexion.prepareStatement( 40 "INSERT INTO Direcciones " + 41 "( PrimerNombre, ApellidoPaterno, Email, NumeroTelefonico ) " + 42 "VALUES ( ?, ?, ?, ? )" ); 43 } // fin de try 44 catch ( SQLException excepcionSql ) 45 { 46 excepcionSql.printStackTrace(); 47 System.exit( 1 ); 48 } // fin de catch 49 } // fin del constructor de ConsultasPersona 50 51 // selecciona todas las direcciones en la base de datos 52 public List< Persona > obtenerTodasLasPersonas() 53 { 54 List< Persona > resultados = null; 55 ResultSet conjuntoResultados = null; 56 57 try Figura 25.31 | Una interfaz que almacena todas las consultas para que las utilice un objeto LibretaDirecciones. (Parte 1 de 4). 25.11 Objetos PreparedStatement 1081 58 { 59 // executeQuery devuelve ResultSet que contiene las entradas que coinciden 60 conjuntoResultados = seleccionarTodasLasPersonas.executeQuery(); 61 resultados = new ArrayList< Persona >(); 62 63 while ( conjuntoResultados.next() ) 64 { 65 resultados.add( new Persona( 66 conjuntoResultados.getInt( "idDireccion" ), 67 conjuntoResultados.getString( "primerNombre" ), 68 conjuntoResultados.getString( "apellidoPaterno" ), 69 conjuntoResultados.getString( "email" ), 70 conjuntoResultados.getString( "numeroTelefonico" ) ) ); 71 } // fin de while 72 } // fin de try 73 catch ( SQLException excepcionSql ) 74 { 75 excepcionSql.printStackTrace(); 76 } // fin de catch 77 finally 78 { 79 try 80 { 81 conjuntoResultados.close(); 82 } // fin de try 83 catch ( SQLException excepcionSql ) 84 { 85 excepcionSql.printStackTrace(); 86 close(); 87 } // fin de catch 88 } // fin de finally 89 90 return resultados; 91 } // fin del método obtenerTodasLasPersonaas 92 93 // selecciona persona por apellido paterno 94 95 public List< Persona > obtenerPersonasPorApellido( String nombre ) 96 { 97 List< Persona > resultados = null; 98 ResultSet conjuntoResultados = null; 99 100 try 101 { 102 seleccionarPersonasPorApellido.setString( 1, nombre ); // especifica el apellido paterno 103 104 // executeQuery devuelve ResultSet que contiene las entradas que coinciden 105 conjuntoResultados = seleccionarPersonasPorApellido.executeQuery(); 106 107 resultados = new ArrayList< Persona >(); 108 109 while ( conjuntoResultados.next() ) 110 { 111 resultados.add( new Persona( 112 conjuntoResultados.getInt( "idDireccion" ), 113 conjuntoResultados.getString( “primerNombre" ), 114 conjuntoResultados.getString( "apellidoPaterno" ), Figura 25.31 | Una interfaz que almacena todas las consultas para que las utilice un objeto LibretaDirecciones. (Parte 2 de 4). 1082 Capítulo 25 Acceso a bases de datos con JDBC 115 conjuntoResultados.getString( "email" ), 116 conjuntoResultados.getString( "numeroTelefonico" ) ) ); 117 } // fin de while 118 } // fin de try 119 catch ( SQLException excepcionSql ) 120 { 121 excepcionSql.printStackTrace(); 122 } // fin de catch 123 finally 124 { 125 try 126 { 127 conjuntoResultados.close(); 128 } // fin de try 129 catch ( SQLException excepcionSql ) 130 { 131 excepcionSql.printStackTrace(); 132 close(); 133 } // fin de catch 134 } // fin de finally 135 136 return resultados; 137 } // fin del método obtenerPersonasPorApellido 138 139 // agrega una entrada 140 public int agregarPersona( 141 String pnombre, String apaterno, String email, String num ) 142 { 143 int resultado = 0; 144 145 // establece los parámetros, después ejecuta insertarNuevaPersona 146 try 147 { 148 insertarNuevaPersona.setString( 1, pnombre ); 149 insertarNuevaPersona.setString( 2, apaterno ); 150 insertarNuevaPersona.setString( 3, email ); 151 insertarNuevaPersona.setString( 4, num ); 152 153 // inserta la nueva entrada; devuelve # de filas actualizadas 154 resultado = insertarNuevaPersona.executeUpdate(); 155 } // fin de try 156 catch ( SQLException excepcionSql ) 157 { 158 excepcionSql.printStackTrace(); 159 close(); 160 } // fin de catch 161 162 return resultado; 163 } // fin del método agregarPersona 164 165 // cierra la conexión a la base de datos 166 public void close() 167 { 168 try 169 { 170 conexion.close(); 171 } // fin de try 172 catch ( SQLException excepcionSql ) Figura 25.31 | Una interfaz que almacena todas las consultas para que las utilice un objeto LibretaDirecciones. (Parte 3 de 4). 25.11 Objetos PreparedStatement 1083 173 { 174 excepcionSql.printStackTrace(); 175 } // fin de catch 176 } // fin del método close 177 } // fin de la interfaz ConsultasPersona Figura 25.31 | Una interfaz que almacena todas las consultas para que las utilice un objeto LibretaDirecciones. (Parte 4 de 4). En las líneas 31 y 32 se invoca el método prepareStatement de Connection para crear la instrucción PreparedStatement llamada seleccionarTodasLasPersonas, la cual selecciona todas las filas en la tabla Direcciones. En las líneas 35 y 36 se crea la instrucción PreparedStatement llamada seleccionarPersonas- PorApellido con un parámetro. Esta instrucción selecciona todas las filas en la tabla Direcciones que coincidan con un apellido específico. Observe el carácter ? que se utiliza para especificar el parámetro apellido. En las líneas 39 a 42 se crea la instrucción PreparedStatement llamada insertarNuevaPersona, concuatro parámetros que representan el primer nombre, apellido paterno, dirección de e-mail y número telefónico para una nueva entrada. De nuevo, observe los caracteres ? que se utilizan para representar estos parámetros. El método obtenerTodasLasPersonas (líneas 52 a 91) ejecuta la instrucción PreparedStatement selec- cionarTodasLasPersonas (línea 60) mediante una llamada al método executeQuery, el cual devuelve un objeto ResultSet que contiene las filas que coinciden con la consulta (en este caso, todas las filas en la tabla Direcciones). En las líneas 61 a 71 se colocan los resultados de la consulta en un objeto ArrayList de objetos Persona, el cual se devuelve en la línea 90 al método que hizo la llamada. El método obtenerPersonasPor- Apellido (líneas 95 a 137) utiliza el método setString de PreparedStatement para establecer el parámetro en seleccionarPersonasPorApellido. Después, en la línea 105 se ejecuta la consulta y en las líneas 107 a 117 se colocan los resultados de la consulta en un objeto ArrayList de objetos Persona. En la línea 136 se devuelve el objeto ArrayList al método que hizo la llamada. El método agregarPersona (líneas 140 a 163) utiliza el método setString de PreparedStatement (líneas 148 a 151) para establecer los parámetros para la instrucción PreparedStatement llamada insertarNueva- Persona. La línea 154 utiliza el método executeUpdate de PreparedStatement para insertar un nuevo registro. Este método devuelve un entero, el cual indica el número de filas que se actualizaron (o insertaron) en la base de datos. El método close (líneas 166 a 176) simplemente cierra la conexión a la base de datos. La clase MostrarLibretaDirecciones La aplicación MostrarLibretaDirecciones (figura 25.32) utiliza un objeto de la clase ConsultasPersona para interactuar con la base de datos. En la línea 59 se crea el objeto ConsultasPersona que se utiliza en la clase MostrarLibretaDirecciones. Cuando el usuario oprime el objeto JButton llamado Explorar todas las entradas, se hace una llamada al manejador botonExplorarActionPerformed (líneas 309 a 335). En la línea 313 se hace una llamada al método obtenerTodasLasPersonas en el objeto ConsultasPersona para obtener todas las entradas en la base de datos. Después, el usuario puede desplazarse a través de las entradas, usando los objetos JButton Anterior y Siguiente. Cuando el usuario oprime el objeto JButton Buscar, se hace una llamada al manejador botonConsultaActionPerformed (líneas 265 a 287). En las líneas 267 y 268 se hace una llama- da al método obtenerPersonasPorApellido en el objeto ConsultasPersona, para obtener las entradas en la base de datos que coincidan con el apellido paterno especificado. Si hay varias entradas de este tipo, el usuario puede desplazarse de una entrada a otra mediante los objetos JButton Anterior y Siguiente. Para agregar una nueva entrada a la base de datos LibretaDirecciones, el usuario puede escribir el primer nombre, apellido paterno, email y número telefónico (el valor de IdDireccion se autoincrementará) en los obje- tos JTextField y oprimir el objeto JButton Insertar nueva entrada. Cuando el usuario oprime este botón, se hace una llamada al manejador botonInsertarActionPerformed (líneas 338 a 352). En las líneas 340 a 342 se hace una llamada al método agregarPersona en el objeto ConsultasPersona, para agregar una nueva entra- da a la base de datos. Después, el usuario puede ver distintas entradas oprimiendo los objetos JButton Anterior o Siguiente, lo cual produce llamadas a los métodos botonAnteriorActionPerformed (líneas 241 a 250) o botonSiguien- 1084 Capítulo 25 Acceso a bases de datos con JDBC 1 // Fig. 25.32: MostrarLibretaDirecciones.java 2 // Una libreta de direcciones simple 3 import java.awt.event.ActionEvent; 4 import java.awt.event.ActionListener; 5 import java.awt.event.WindowAdapter; 6 import java.awt.event.WindowEvent; 7 import java.awt.FlowLayout; 8 import java.awt.GridLayout; 9 import java.util.List; 10 import javax.swing.JButton; 11 import javax.swing.Box; 12 import javax.swing.JFrame; 13 import javax.swing.JLabel; 14 import javax.swing.JPanel; 15 import javax.swing.JTextField; 16 import javax.swing.WindowConstants; 17 import javax.swing.BoxLayout; 18 import javax.swing.BorderFactory; 19 import javax.swing.JOptionPane; 20 21 public class MostrarLibretaDirecciones extends JFrame 22 { 23 private Persona entradaActual; 24 private ConsultasPersona consultasPersona; 25 private List< Persona > resultados; 26 private int numeroDeEntradas = 0; 27 private int indiceEntradaActual; 28 29 private JButton botonExplorar; 30 private JLabel etiquetaEmail; 31 private JTextField campoTextoEmail; 32 private JLabel etiquetaPrimerNombre; 33 private JTextField campoTextoPrimerNombre; 34 private JLabel etiquetaID; 35 private JTextField campoTextoID; 36 private JTextField campoTextoIndice; 37 private JLabel etiquetaApellidoPaterno; 38 private JTextField campoTextoApellidoPaterno; 39 private JTextField campoTextoMax; 40 private JButton botonSiguiente; 41 private JLabel etiquetaDe; 42 private JLabel etiquetaTelefono; 43 private JTextField campoTextoTelefono; 44 private JButton botonAnterior; 45 private JButton botonConsulta; 46 private JLabel etiquetaConsulta; 47 private JPanel panelConsulta; 48 private JPanel panelNavegar; 49 private JPanel panelMostrar; 50 private JTextField campoTextoConsulta; 51 private JButton botonInsertar; 52 53 // constructor sin argumentos 54 public MostrarLibretaDirecciones() 55 { 56 super( "Libreta de direcciones" ); 57 58 // establece la conexión a la base de datos y las instrucciones PreparedStatement 59 consultasPersona = new ConsultasPersona(); Figura 25.32 | Una libreta de direcciones simple. (Parte 1 de 7). 25.11 Objetos PreparedStatement 1085 60 61 // crea la GUI 62 panelNavegar = new JPanel(); 63 botonAnterior = new JButton(); 64 campoTextoIndice = new JTextField( 2 ); 65 etiquetaDe = new JLabel(); 66 campoTextoMax = new JTextField( 2 ); 67 botonSiguiente = new JButton(); 68 panelMostrar = new JPanel(); 69 etiquetaID = new JLabel(); 70 campoTextoID = new JTextField( 10 ); 71 etiquetaPrimerNombre = new JLabel(); 72 campoTextoPrimerNombre = new JTextField( 10 );