Acceso a bases de datos con JDBC
Introducción
Una base de datos es una colección de información organizada
de tal forma, que un programa puede extraer segmentos de datos
según lo requiera. Las bases de datos tradicionales se organizan
en campos, registros y archivos.
Un DBMS (database management system) es un software que
administra las bases de datos y proporciona a usuarios y
programadores, un mecanismo sistematizado para crear, obtener,
actualizar y gestionar datos. Controla accesos, concurrencia,
respaldos, etc.
SQL es el lenguaje estándar internacional utilizado para la
consulta y manipulación de información en bases de datos
relacionales.
Para tener acceso a la información de la base de datos
(relacionales), los programas se conectan e interactúan a través
de una interface, que es un software que habilita la comunicación
entre un DBMS y un programa.
El JDBC (Java DataBase Connectivity) es una interface de
programación de aplicaciones (API) que permite al programador
de Java, conectarse e interactuar con una base de datos en un
DBMS particular. Esta interacción permite la manipulación de la
base de datos y la gestión de su información (a través de SQL,
stored procedures, etc.)
Bases de datos relacionales
En términos simples, una base de datos relacional es aquella que
presenta información en tablas, mismas que almacenan
información de un tema común. Los datos en las tablas pueden
relacionarse por conceptos de llaves y esa relación permite la
recuperación de información.
Las tablas están compuestas por filas y columnas. Las columnas
guardan campos o atributos, los que se refieren a una propiedad
o característica que se quiere guardar en una tabla (por ejemplo,
cédula, dirección, teléfono).
Las filas, llamadas tuplas o registros, representan una estructura
de datos simple que referencia información para cada campo en
una instancia particular.
Una clave primaria proporciona un único valor que no puede
estar duplicado en otra fila de la misma tabla.
La clave primaria puede estar compuesta por una o varias
columnas. Cada columna en una clave primaria debe tener un
valor (no puede ser null) y debe ser único dentro de la tabla.
Esto es conocido como la Regla de Integridad de Entidad.
Una clave foránea es un campo una tabla que corresponde a una
clave primaria de otra tabla. Esto es conocido como
la Regla de Integridad Referencial.
Las tablas pueden tener muchas relaciones. Una relación de uno
a muchos indica que un registro de una tabla puede tener
muchas filas asociadas a su clave primaria en otra tabla.
Las claves foráneas relacionan información de multiples tablas y
obtienen información a través de consultas
SQL
Clausula SELECT
La forma básica de una consulta es
SELECT * FROM NombreTabla
Donde el asterisco (*) indica que todas las columnas desde la
tabla NombreTabla se deben seleccionar.
NombreTabla especifica la tabla de la base de datos desde la
cual se recuperarán las filas
El asterisco puede reemplazarse con los nombres de los campos
(separados por comas) en el caso que no se quieran recuperar
todas las columnas.
.
Claúsula WHERE
La clausula opcional WHERE en una consulta establece un
criterio de selección de forma que únicamente se recuperen
aquellas filas que la cumplan
La forma básica de una consulta con criterio de selección es
SELECT NombCol1, NombCol2, ...
FROM NombreTabla
WHERE criterio
La clausula WHERE puede contener operadores lógicos <, >, <=,
>=, =, <>, AND, OR, XOR, LIKE, etc.
El operador LIKE es usado para el patrón de cadena coincidente
con los caracteres comodín por ciento (%) y subrayado (_).
Un carácter por ciento (%) en un patrón indica que una cadena
que concuerda con el patrón puede tener cero o más caracteres
en la posición del carácter comodín.
WHERE Nombre LIKE ‘%ANDRES%’
Un subrayado (_) en el patrón indica que un único carácter puede
estar en aquella posición del patrón.
Clausula ORDER BY
El resultado de una consulta puede ser ordenado con la clausula
ORDER BY.
SELECT NombCol1, NombCol2, ...
FROM NombreTabla
ORDER BY NombCol ASC
SELECT NombCol1, NombCol2, ...
FROM NombreTabla
ORDER BY NombCol DESC
El orden de la tabla puede ser ascedente o descendente, según
se especifique. Por defecto será ascendente.
El campo (o campos) especificados luego de la sentencia
ORDER BY, definirán la secuencia de ordenamiento.
ORDER BY NombCol1, NombCol2 …
Las claúsulas ASC y DESC pueden ser aplicadas para cada
campo
ORDER BY NombCol1 ASC, NombCol2 DESC
Consulta de datos desde múltiples tablas: INNER JOIN
Una INNER JOIN retorna todas las filas de múltiples tablas donde
la condición de JOIN se cumpla.
La forma básica para el operador INNER JOIN es:
SELECT Col1, Col2, ...
FROM Tabla1
INNER JOIN Tabla2
ON Tabla1.NombCol = Tabla2.NombCol
La clausula ON especifica las columnas de cada tabla que son
comparadas para determinar cuales filas serán unidas.
Si una sentencia SQL usa columnas con el mismo nombre desde
múltiples tablas, el nombre de la columna debe especificarlo junto
con el nombre de la tabla.
Claúsula INSERT
Una sentencia INSERT ingresa una nueva fila en una tabla. La
forma básica de esta sentencia es:
INSERT INTO NombTab (Col1, Col2, ..., ColN)
VALUES (Val1, Val2, ..., ValN)
Donde NombTab es la tabla en la cual se inserta la fila. La
NombTab es seguida por una lista de las columnas de la tabla,
separadas por comas. Está seguida por la palabra clave
VALUES, luego de la cual se ingresa cada valor correspondiente
a las columnas especificadas.
En varios DBMSs, es obligatorio ingresar sólo los campos de
clave primaria y los que no aceptan null.
Para delimitar cadenas se usa un apostrofe ('). Para especificar
una cadena conteniendo un apostrofe en SQL, escape el
apostrofe con otro apostrofe (es decir, '').
Clausula UPDATE
Una sentencia UPDATE modifica datos en una tabla. La forma
básica de una sentencia UPDATE es:
UPDATE NombTab
SET Col1 = Val1, Col2 = Val2, ..., ColN = ValN
WHERE criterio
Donde NombTab es la tabla en la cual se actualizarán los datos.
La NombTab es seguida por la palabra clave SET y una lista
separada por comas de los pares NombCol = Valor.
La clausula opcional WHERE determina cuales filas actualizar.
UPDATE Empleados SET Nombre = ‘Ana’ WHERE Cedula =
‘XXXXXX’
Clausula DELETE
Una sentencia DELETE elimina filas de una tabla. La forma más
simple de una sentencia DELETE es:
DELETE FROM NombTab WHERE criterio
Donde NombTab es la tabla desde la cual borrar una fila (o más
filas). La clausula opcional WHERE determina cuales filas se
borrarán.
Si esta clausula es omitida, todas las filas de la tabla serán
borradas.
SENTENCIAS DDL
Create database
Crea una base de datos nueva
CREATE DATABASE database
Drop database
Elimina una base de datos
DROP DATABASE IF EXISTS database
Create table
Crea una tabla dentro de la base de datos
CREATE TABLE Titulos
(
ISBN varchar(20) NOT NULL PRIMARY KEY,
Titulo varchar(100) NOT NULL,
NumeroEdicion int NOT NULL,
Copyright varchar(4) NOT NULL
);
CREATE TABLE 'alumnos' (
'CODIGO' bigint(20) NOT NULL,
'APELLIDOS' varchar(60) NOT NULL,
'NOMBRES' varchar(60) NOT NULL,
'CEDULA' varchar(10) DEFAULT NULL,
...
PRIMARY KEY ('CODIGO')
)
Drop table
Elimina una tabla de la base de datos
DROP TABLE tabla
Alter table
Modifica una tabla de la base de datos. Pueden existir varias
acciones:
CREATE TABLE tabla1 (a INTEGER, b CHAR(10));
Renombra la tabla
ALTER TABLE tabla1 RENAME tabla2
Cambia el campo “a” a TINYINT, renombra el campo “b” a “c” y lo
cambia de CHAR(10) a CHAR(20)
ALTER TABLE tabla2 MODIFY a TINYINT NOT NULL, CHANGE
b c CHAR(20);
Añade la columna “d” como INTEGER
ALTER TABLE tabla2 ADD d INTEGER
Define la columna “d” como índice y pone al campo “a”
como único.
ALTER TABLE tabla2 ADD INDEX (d), ADD UNIQUE (a);
Quita la columna “c”
ALTER TABLE tabla2 DROP COLUMN c;
Añade un INTEGER AUTO_INCREMENT llamado “c”.
Establece clave primaria
ALTER TABLE tabla2 ADD c INT UNSIGNED NOT NULL
AUTO_INCREMENT, ADD PRIMARY KEY (c);
Truncate table
Elimina la tabla y la vuelve a crear
TRUNCATE TABLE tabla
Instalación de MySQL
Manejando datos con JDBC
Conectar con una base de datos
El paquete java.sql contiene clases e interfaces para acceder
bases de datos relacionales en Java. En general se utiliza el
siguiente esquema para el acceso a una base de datos:
1. Registrar la clase del JDBC
Class.forName("com.mysql.jdbc.Driver");
2. Crear la conexión
con = DriverManager.getConnection("jdbc:mysql://localhost/sistema?...);
3. Generar un statement
Statement stmt = con.createStatement();
4. Ejecutar el statement (especificando comando)
ResultSet rs = stmt.executeQuery("SELECT * FROM sistema.alumnos");
5. Procesar resultSet (en caso de consulta)
while (rs.next()) {
String field1 = rs.getString(1) ;...
6. Cerrar los componentes
rs.close();
stmt.close();
con.close();
Un objeto Connection maneja la conexión entre un programa
Java y una base de datos. El objeto conexión permite que el
programa cree sentencias SQL para acceder datos.
El método getConnection de DriverManager intenta conectar a
una base de datos. Utiliza un URL que especifica el protocolo de
comunicaciones (jdbc), el subprotocolo de comunicación (la base
de datos) y otros parámetros como localización, hosts, puerto,
nombre de la base de datos.
// establish connection to database
DriverManager.getConnection(DATABASE_URL,'userid','passwor
d');
JDBC URL
MySQL com.mysql.jdbc.Driver jdbc:mysql://hostname/ databaseName
jdbc:oracle:thin:@hostname:port
ORACLE oracle.jdbc.driver.OracleDriver
Number:databaseName
jdbc:db2:hostname:port
DB2 COM.ibm.db2.jdbc.net.DB2Driver
Number/databaseName
com.microsoft.sqlserver.jdbc.SQLSe
SQLServer jjdbc:sqlserver://hostname:port
rverDriver
El método createStatement de Connection crea un objeto
Statement, que puede ser usado para enviar sentencias SQL a
la base de datos.
// create Statement for querying database
statement = connection.createStatement();
El método executeQuery de Statement ejecuta una consulta y
devuelve un objeto ResultSet conteniendo el resultado de la
consulta.
Los métodos de ResultSet permiten que un programa manipule
los resultados de la consulta.
Un objeto ResultSetMetaData describe el contenido de un
ResultSet. Los programas pueden usar metadatos, mediante
programación, para obtener información acerca los nombres y
tipos de las columnas del ResultSet.
// query database
resultSet = statement.executeQuery(
"SELECT AuthorID, FirstName, LastName FROM Authors" );
ResultSetMetaData metaData = resultSet.getMetaData();
El método getColumnCount de ResultSetMetaData recupera el
número de columnas del ResultSet.
int numberOfColumns = metaData.getColumnCount();
El método next de ResultSet posiciona el cursor del ResultSet en
la siguiente fila y devuelve true si la fila existe; de lo contrario, el
devuelve false. Este método debe ser llamado para iniciar el
procesamiento de un ResultSet porque el cursor esta inicialmente
posicionado antes de la primera fila.
while(resultSet.next() )
{
for ( int i = 1; i <= numberOfColumns; i++ )
System.out.printf( "%-8s\t", resultSet.getObject( i ));
System.out.println();
}
Es posible extraer cada columna del ResultSet como un tipo
especifico de Java. El método getColumnType de
ResultSetMetaData devuelve una constante Types (paquete
java.sql) indicando el tipo de la columna.
ResultSetMetaData metaData = resultSet.getMetaData();
int numberOfColumns = metaData.getColumnCount();
metaData.getColumnName( i )
Los métodos get de ResultSet típicamente reciben como un
argumento un número de columna (como un int) o un nombre
(como un String) indicando el valor de la columna que se quiere
obtener.
Los números de fila y columna del ResultSet inician en 1.
Cada objeto Statement puede abrir sólo un ResultSet en un
momento. Cuando un Statement devuelve un nuevo ResultSet, el
Statement cierra el ResultSet anterior.
El método createStatement de Connection tiene una versión
sobrecargada que recibe el tipo de resultado y la concurrencia del
result set.
Statement stmt = conn.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
Entre los tipos de resultado se pueden tener están:
TYPE_FORWARD_ONLY: El cursor sólo puede moverse
para adelante dentro del ResultSet.
TYPE_SCROLL_INSENSITIVE: El cursor se puede mover
hacia adelante o hacia atrás. El conjunto de resultados no
es sensible a los cambios realizados en la base de datos
(por otras aplicaciones) que ocurren luego de la creación del
ResultSet.
TYPE_SCROLL_SENSITIVE: El cursor se puede mover
hacia adelante y hacia atrás. El result set es sensible a los
cambios realizados en la base de datos que ocurren luego
de la creación del ResultSet.
La concurrencia del ResultSet puede ser de dos tipos:
CONCUR_READ_ONLY: El ResultSet es sólo de lectura.
CONCUR_UPDATABLE: Crea un ResultSet actualizable.
Algunos drivers JDBC no soportan ResultSets, desplazadores o
actualizadores.
Ver los archivos:
TestConnection.java
EjemplosSQL.java
Libros.sql
MostrarAutores.java
Consultando la base de datos
El método getColumnClass de TableModel devuelve un objeto
Class que representa la superclase de todos los objetos en una
columna particular.
Un JTable usa esta información para establecer el renderizador
de celdas por defecto y un editor de la celda de esa columna en
un JTable.
El método getColumnClassName de ResultSetMetaData
obtiene el nombre de clase completamente calificado de una
columna.
El método getColumnCount de TableModel devuelve el número
de columnas en el ResultSet subyacente.
El método getColumnName de TableModel devuelve el nombre
de la columna en el ResultSet subyacente.
El método getColumnName de ResultSetMetaData obtiene el
nombre de columna del ResultSet.
El método getRowCount de TableModel devuelve el número de
filas en el ResultSet del modelo.
El método getValueAt de TableModel devuelve el Object de una
particular fila y columna del ResultSet subyacente del modelo.
El método absolute del ResultSet posiciona el cursor del
ResultSet en un fila especifica.
El método fireTableStructureChanged de AbstractTableModel
notifica que cualquier JTable con un determinado objeto
TableModel como modelo que los datos en el modelo han
cambiado.
Ver los archivos:
TablaAbstracta.java
TablaDatos.java
ModeloTablaConjuntoResultado.java
MostrarResultadosConsulta.java
Interface RowSet
La interface RowSet configura una conexión a una base de datos
y ejecuta operaciones sobre ella. Actúa como un wrapper de un
ResultSet para hacerlo compatible con operaciones como la
serialización (ResultSet mantiene la conexión con la base de
datos) o su inclusión como componente.
JdbcRowSet rowSet = new JdbcRowSetImpl();
rowSet.setUrl(URL_BASEDATOS);
rowSet.setUsername(NOMBRE_USUARIO);
rowSet.setPassword(PASSWORD_USUARIO);
rowSet.setCommand("SELECT * FROM Autores");
rowSet.execute();
Los RowSets pueden ser de dos tipos:
Conectados. El objeto RowSet realiza la conexión con la
base de datos y mantiene esa conexión a lo largo de su
ciclo de vida.
Desconectados. El objeto RowSet realiza la conexión con la
base de datos, lee la información y cierra la conexión.
Todavía puede realizar cambios sobre los datos en
memoria, pero debe restablecer la conexión para hacer
commit de estos cambios.
JdbcRowSet, un RowSet conectado, envuelve un objeto
ResultSet y permite el desplazamiento y actualización de
información
A diferencia de un objeto ResultSet, un objeto JdbcRowSet es
desplazador y actualizador por implícito. Funciona como un
wrapper para usar un ResultSet como un componente de
JavaBeans.
CachedRowSet, es un RowSet desconectado. Almacena los
datos de un ResultSet en memoria. Un CachedRowSet es
desplazador/actualizador y serializable.
Ver el archivo:
PruebaJdbcRowSet.java
Java DB/Apache Derby
A partir del JDK 6, Sun Microsystems empaqueta junto con el
JDK la base de datos Java puro de código abierto, Java DB
(Apache Derby).
Instalar Apache Derby
PreparedStatements
Las PreparedStatements permiten crear sentencias SQL
precompiladas que se ejecutan más eficientemente que los
Statements.
A diferencia de los Statements, estos objetos generan una
sentencia SQL cuando se crean y la envían al DBMS, donde es
compilada. Como resultado el Prepared Statement contiene una
sentencia SQL precompilada, es decir, la sentencia tiene un plan
de ejecución elaborado y puede reutilizarse (lo cual implica una
mayor velocidad en la consulta).
Las PreparedStatements pueden tener parámetros, así la misma
consulta puede ejecutarse con diferentes argumentos.
Un parámetro es especificado con una marca de interrogación (?)
en la sentencia SQL.
Antes de ejecutar una PreparedStatements, debe usar los
métodos set de PreparedStatements para especificar los
argumentos.
insertarNuevaPersona = conexion.prepareStatement(
"INSERT INTO Direcciones (PrimerNombre, ApellidoPaterno,
Email, NumeroTelefonico) VALUES (?, ?, ?, ?)");
PreparedStatement insertarNuevaPersona = null;
insertarNuevaPersona = conexion.prepareStatement(
sql);
....
insertarNuevaPersona.setString(1, pnombre);
insertarNuevaPersona.setString(2, apaterno); ...
resultado = insertarNuevaPersona.executeUpdate();
El primer argumento del método setString de
PreparedStatements representa el número del parámetro y su
valor.
Los números de parámetros son contados desde 1, iniciando con
la primera marca de interrogación (?).
La interface PreparedStatement proporciona métodos set para
cada tipo SQL soportado.
Direcciones.sql
Persona.java
ConsultasPersona.java
MostrarLibretaDirecciones.java
Procedimientos almacenados
JDBC permite que los programas invoquen procedimientos
almacenados usando objetos CallableStatement.
CallableStatement stmt=con.prepareCall("{call insertR(?,?)}");
CallableStatement puede especificar parámetros de entrada.
CallableStatement puede especificar parámetros de salida en los
cuales un procedimiento almacenado puede colocar valores de
retorno.
Procesamiento de transacciones
El procesamiento de transacciones permite que un programa que
interactúe con una base de datos trate una operación (u
operaciones) formando una sola “transacción”
Al final de una transacción, una decisión puede ser hecha para
commit (hacer) o roll back (retroceder) la transacción.
Committing una transacción finaliza la operación(es) de base de
datos y no puede ser revertido.
Rolling back una transacción deja la base de datos en su estado
anterior a la operación de base de datos.
Java proporciona procesamiento de transacciones vía métodos
de la interfase Connection.
El método setAutoCommit especifica que cada sentencia SQL
de commits después que se complete.
Cuando autocommit es deshabilitado, el programa debe seguir a
la última sentencia SQL en la transacción con una llamada al
método commit de Connection (para commit los cambios
a la base de datos) o al método rollback de
Connection (para regresar la base de datos a su estado anterior a
la transacción).
El método getAutoCommit determina el estado de autocommit
para la Connection.
con.setAutoCommit(false);
PreparedStatement.executeUpdate();
con.commit();
con.rollback();
con.setAutoCommit(true);