Access en Java con Ucanaccess de 64 bits

Ejercicio de Java para consola: conectar con una base de datos de Microsoft Access mediante el controlador JDBC UCanAccess, emitir sentencias SQL a la base de datos y mostrar los resultados, ejecutar el programa desde línea de comandos junto con las dependencias, crear archivos de comando para ejecutar el programa.

La conexión JDBC-ODBC no se incluye desde Java 8. Existen algunos controladores JDBC propietarios para conectar con MS Access pero el proyecto UCanAccess está activo, es open source, funciona bien, es sencillo de utilizar y proporciona un controlador JDBC generado sobre código de Jackcess.

Nota: Jackcess a diferencia de UCanAccess es una librería de código Java diseñada para leer y escribir bases de datos de MS Access que no es un controlador JDBC sino una implementación directa de las características disponibles para interactuar con bases de datos de MS Access. Su licencia es del tipo Apache License.

Base de datos

Se utiliza una base de datos de MS Access con nombre 50empresas.accdb, tiene una única tabla llamada Contactos y esta tabla tiene 3 campos: Id (autonumérico) / Nombre (texto) / Telefono (texto).

Dependencias

Se necesita ucanaccess.jdbc.UcanaccessDriver, el controlador que permite acceder a MS Access desde Java, y la cadena apropiada para conectar con la base de datos, además de 5 archivos JAR que son necesarios como dependencias.

  • UCanAccess (ucanaccess-x.x.x.jar)
  • HSQLDB (hsqldb-x.x.x.jar)
  • Jackcess (jackcess-x.x.x.jar)
  • commons-lang (commons-lang3-x.x.x.jar)
  • commons-logging (commons-logging-x.x.jar).

Se pueden descargar desde el repositorio Maven pero también están incluidos en UCanAccess. Cuando descomprimes el paquete de la distribución obtienes algo como ésto:

ucanaccess 5.0.1 package
├── lib
│   ├── commons-lang3-3.8.1.jar
│   ├── commons-logging-1.2.jar
│   ├── hsqldb-2.5.0.jar
│   └── jackcess-3.0.1.jar
└── ucanaccess-5.0.1.jar

Estos archivos han de ser llamados al ejecutar el programa desde la línea de comandos.

Compilar el programa

Se hace de la forma habitual, con el comando javac AccessEnJava.java en la carpeta en la que está el archivo de código.

Ejecutar el programa con las dependencias

En este ejercicio el código fuente AccessEnJava.java está en la carpeta del disco D:\Java\JDBC y los 5 archivos JAR y la base de datos 50empresas.accdb están en la carpeta D:\Java\JDBC\lib. Para ejecutar el programa desde consola hay que incluir la clase principal, como se hace habitualmente, y también las dependencias que en este caso son archivos JAR. Esto es así porque estamos trabajando de la forma más simple, con editor de texto y línea de comandos. Si se trabaja con algún entorno integrado la adición de dependencias se realiza desde las herramientas del propio entorno y el resultado de la compilación lleva incorporado lo necesario para ser ejecutado.

Para llamar a las dependencias se usa el ejecutable java con el modificador -cp seguido de: ruta a la carpeta actual (D:\Java\JDBC en este ejemplo) + ruta a cada uno de los archivos JAR requeridos + clase principal. El comando es diferente dependiendo del sistema operativo.
En Windows hay que utilizar (va todo en una sola línea):

java -cp D:/Java/JDBC;D:/Java/JDBC/lib/ucanaccess-5.0.1.jar;D:/Java/JDBC/lib/commons-lang3-3.8.1.jar;D:/Java/JDBC/lib/commons-logging-1.2.jar;D:/Java/JDBC/lib/hsqldb-2.5.0.jar;D:/Java/JDBC/lib/jackcess-3.0.1.jar AccessEnJava

Observa que las rutas están separadas por ; y no hay espacios entre ellas pero sí entre las rutas y el nombre de la clase que va al final. Como es engorroso escribir o copiar todo el texto cada vez que se ejecuta el programa, existe la opción de crear un archivo de comandos con extensión .bat desde el que iniciarlo de forma cómoda con doble clic. En este caso el texto del archivo de comandos ha de ser:

@echo off
cd C:\Users\pol\Documents\Java\JDBC\
java -cp C:/Users/pol/Documents/Java/JDBC;C:/Users/pol/Documents/Java/JDBC/lib/ucanaccess-5.0.1.jar;C:/Users/pol/Documents/Java/JDBC/lib/commons-lang3-3.8.1.jar;C:/Users/pol/Documents/Java/JDBC/lib/commons-logging-1.2.jar;C:/Users/pol/Documents/Java/JDBC/lib/hsqldb-2.5.0.jar;C:/Users/pol/Documents/Java/JDBC/lib/jackcess-3.0.1.jar AccessEnJava
REM pause
REM exit

La línea REM pause se puede dejar así o descomentarla quitando REM, lo que hace es parar el flujo pidiendo pulsar una tecla para seguir.

El comando equivalente de Terminal en macOS sería (va todo en una línea):

java -cp .:./lib/ucanaccess-5.0.1.jar:./lib/commons-lang3-3.8.1.jar:./lib/commons-logging-1.2.jar:./lib/hsqldb-2.5.0.jar:./lib/jackcess-3.0.1.jar AccessEnJava

Observa que el punto refiere a la carpeta actual y que el separador de rutas es : en lugar de ; como en Windows. Se puede generar un archivo de comandos con extensión .sh para que sea más cómoda la ejecución del programa:

#!/bin/bash
java -cp .:./lib/ucanaccess-5.0.1.jar:./lib/commons-lang3-3.8.1.jar:./lib/commons-logging-1.2.jar:./lib/hsqldb-2.5.0.jar:./lib/jackcess-3.0.1.jar AccessEnJava

En este caso en lugar de doble clic hay que ejecutar el archivo .sh directamente en Terminal precedido de ./ seguido del nombre del archivo.

Importación de paquetes

Hay que importar los paquetes para la conexión con MS Access y el envío de comandos SQL además de la clase Scanner que permite recibir desde teclado (para detener el flujo del programa hasta que el usuario pulsa una tecla).

// paquetes para la conexion con MS Access y comandos SQL
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.io.*;
// paquete para usar la clase Scanner que permite recibir desde teclado
import java.util.Scanner;

Se utilizan 3 variables para procesar la tarea: la conexión con la BD, la sentencia SQL y el resultado obtenido con las filas devueltas.

// variables conexion con la BD, sentencias SQL y filas obtenidas
Connection conectar = null;
Statement sentencia = null;
ResultSet resultado = null;
// variable para detectar pulsaciones de teclas, se usa para detener
// el flujo del programa hasta que el usuario pulse una tecla
Scanner s = new Scanner(System.in);

Conexión con la base de datos

Primero hay que registrar el controlador UCanAccess.

// registrar la clase JDBC driver de Ucanaccess
Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");

La cadena de conexión se construye con jdbc:ucanaccess:// seguido de la ruta al archivo. Para no dejar la ruta configurada como una constante se recurre al método getAbsolutePath que devuelve la ruta a la carpeta de trabajo.

// obtener la ruta absoluta a la carpeta de trabajo del proyecto
// se emplea el truco de crear nuevo archivo y obtener su ruta
String ruta = new File(".").getAbsolutePath();
// getAbsolutePath devuelve la ruta a la carpeta pero agrega un punto al final
// quitamos ese ultimo caracter con substring y length
ruta = ruta.substring(0, ruta.length()-1);
// y se agrega el nombre de la BD de MS Access
// se usa File.separatorChar que coloca \ o / dependiendo del sistema operativo
ruta = ruta + "lib" + File.separatorChar + "50empresas.accdb";
// Mensaje informativo
System.out.println ("Ruta a la base de datos: " + ruta + " \nPulsa una tecla para continuar...");
//String ruta = "D:/JDBC/50empresas.accdb";
String dbURL = "jdbc:ucanaccess://" + ruta;

La conexión se crea con la clase DriverManager a la que se le pasa como parámetro la ruta al origen de los datos.

// crear la conexion usando la clase DriverManager
conectar = DriverManager.getConnection(dbURL);

Pulsa una tecla para seguir…

Para obtener este efecto se importa la clase Scanner, se declara con el nombre s y se utiliza cuando hace falta instanciando una cadena nueva, cada vez con un nombre diferente, que recoge la variable s (la pulsación desde teclado).

Scanner s = new Scanner(System.in);
// ...
// se para hasta pulsar una tecla
String una = s.nextLine();
// ...
// se para hasta pulsar una tecla
String dos = s.nextLine();

Objetos de comando SQL

Los objetos de comando SQL (statement) tienen distintos métodos de ejecución:

  • ResultSet executeQuery() ejecuta una sentencia SQL y devuelve el ResultSet (tabla con las filas devueltas por una consulta SQL) generado por la consulta, se usa para leer el contenido de la tabla y mostrar los registros (sentencias SELECT)
  • int executeUpdate() ejecuta una sentencia SQL que ha de ser INSERT, UPDATE o DELETE, se usa para modificar el contenido de la tabla y devuelve el número de filas afectadas
  • boolean execute() ejecuta una sentencia SQL, es true si la instrucción devuelve un conjunto de resultados y false si devuelve un recuento de actualizaciones o no hay ningún resultado.

Aquí se crea la sentencia con el método createStatement de la conexión y el comando devuelve un ResultSet, la sentencia es del tipo SELECT por lo que el comando es del tipo executeQuery. Los registros se muestran recorriendo con un bucle while el ResultSet con su método getInt() al que se pasa el índice de cada columna de la tabla y devuelve el valor de esa celda.

// MOSTRAR TODOS LOS REGISTROS
// crear la sentencia SQL
sentencia = conectar.createStatement();
resultado = sentencia.executeQuery("SELECT Id, Nombre, Telefono FROM Contactos");
// formatear la presentacion de los registros de la tabla
System.out.println("Id\tTel\u00e9fono\tNombre");
System.out.println("==\t========\t======");
while(resultado.next()) {
System.out.println(resultado.getInt(1) + "\t" + resultado.getString(3) + "\t" + resultado.getString(2));
}

Lo que se obtiene por pantalla en consola con estas primeras líneas de código es esto:

Ruta a la base de datos: D:\Java\JDBC\lib\50empresas.accdb
Pulsa una tecla para continuar...

Conexión abierta.
Se van a mostrar los 50 registros de la tabla.
SELECT Id, Nombre, Telefono FROM Contactos
Pulsa una tecla para continuar...

Id      Teléfono        Nombre
==      ========        ======
1       966521455       AEK Goup Inc.
2       944444102       ACE Hardware CO.
3       963325874       ADI Systems Inc.
4       986523365       Administaff Inc.
5       923656987       ADVO Inc.
6       956231487       Aeroquip - Vickers Inc.
7       933659214       LST IND. CO
8       956231487       Agway Inc.
9       912548758       Air Products and Chemicals Inc.
10      965235898       Airborne Freight Corp.
...

El ejercicio continúa con nuevas sentencias SQL y la presentación de los resultados en pantalla. Se prueban sentencias SELECT con BETWEEN (comando executeQuery), sentencias INSERT y UPDATE (comandos executeUpdate), etc. Al final se vacían los recursos utilizados (statement, ResultSet) y se cierra la conexión.

Código completo del archivo Java

Descarga del código fuente

Puedes descargar el código junto con la base de datos desde aquí.