Access en Java con puente ODBC de 32 bits

Conectar con una base de datos de Microsoft Access por medio del puente JDBC-ODBC configurando el origen de los datos en el panel de control ODBC de 32 bits mostrando los registros obtenidos desde consultas SQL con Java 7

Requisitos previos

El puente JDBC-ODBC ha dejado de estar disponible en Java 8 por lo que para poder utilizarlo hay que tener Java 7 o versión anterior. Aunque se trata de un método obsoleto y poco eficiente de acceder a bases de datos de Microsoft Access desde Java, todavía hay usuarios que lo utilizan y que no desean migrar sus programas a controladores propios del lenguaje, libres (ucanaccess, jackcess…) o comerciales.

En Windows 10 están disponibles en las herramientas administrativas los paneles de control ODBC. Hay 2 versiones, para 32 y para 64 bits. Microsoft Access usa un controlador de 32 bits por lo que se necesita instalar Java 7 para 32 bits y abrir el panel ODBC de 32 bits, sin estos 2 requisitos falla el acceso a las bases de datos (BD) desde Java por este método. El panel ODBC se puede encontrar en las herramientas administrativas o tecleando en el menú Inicio > Buscar «Orígenes de datos…» que muestra las 2 opciones:

  • Orígenes de datos ODBC (32 bits)
  • Orígenes de datos ODBC (64 bits).

Registrar la base de datos

Al abrir el administrador de orígenes de datos ODBC de 32 bits hay que ir a la pestaña DSN de sistema:

  • Pulsas en Agregar
  • Eliges el controlador «Microsoft Access Driver (.mdb,.accdb)» > Pulsas en Finalizar
  • En Nombre del origen de datos escribes el nombre que deseas darle, no es necesario que coincida con el archivo de Access y no lleva extensión, en este ejercicio lo he llamado BD1, este es el DSN (data source name) que utilizan las aplicaciones para solicitar una conexión a un origen de datos ODBC, es un nombre simbólico que representa la conexión ODBC
  • Con el botón Seleccionar buscas el archivo .mdb que estará disponible por medio de ODBC
  • En Bases de datos del sistema: ninguna
  • Pulsas Aceptar y no es necesario configurar nada más.

Con ello se genera un origen de datos con el nombre BD1 que por medio de ODBC hace accesible la BD de Microsoft Access a Java gracias a su librería JDBC-ODBC. La BD se llama Access-jdbc.mdb. Tiene una única tabla llamada Tabla1 con 3 campos: Id, Nombre y Teléfono. Se adjunta al final del artículo junto con el código.

Código Java

Dejo a un lado la parte del código que no está directamente relacionado con el puente JDBC-ODBC con objetos JPanel, JLabel, JButton y JTextArea y aspectos de su diseño (posición, letra, etc.) para centrarme exclusivamente en el objeto del artículo.

Para obtener la ruta a la BD, que en mi disco está situada en una carpeta 2 niveles de directorio por encima de la carpeta de la aplicación, empleo el método getAbsolutePath que me permite obtener la ruta absoluta a la carpeta de trabajo del proyecto, para ello empleo el truco de crear un archivo nuevo referido al fichero simbólico . y luego recoger sus características, el fichero . hace referencia al directorio actual por lo que leyendo dicho fichero podemos pedir su ruta. getAbsolutePath devuelve la ruta pero agrega un punto al final, quito ese último carácter con substring y length. Y para subir 2 niveles en el árbol de directorios utilizo el método substring devolviendo la cadena que hay antes del último carácter File.separator que en sistemas Windows es la barra invertida.

// nombre del archivo .mdb
String db = "Access-jdbc.mdb";
// obtener la ruta absoluta a la carpeta de trabajo del proyecto para ello
String ruta = new File(".").getAbsolutePath();
// quitar el ultimo caracter con substring y length
ruta = ruta.substring(0, ruta.length()-1);
// subir 2 veces en el arbol de directorios para llegar a la carpeta con la base de datos
ruta=ruta.substring(0, ruta.lastIndexOf(File.separator));
ruta=ruta.substring(0, ruta.lastIndexOf(File.separator));
// agregar el nombre de la base de datos al final de la ruta obtenida
ruta = ruta + File.separator + db;

La cadena de conexión se construye con el nombre simbólico DSN en lugar del nombre del archivo .mdb y su contenido básico es «jdbc:odbc:nombre_DSN«. Hay que registrar el driver JDBC usando el cargador de clases Class.forName y generar la conexión pasando al driver la cadena básica que finaliza con el nombre DSN. Las 2 cadenas vacías que se ven en la conexión corresponden a usuario y contraseña de acceso a la BD en caso de que existan.

String url = "jdbc:odbc:BD1";
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
con = DriverManager.getConnection(url, "", "");

He probado con otras cadenas de conexión disponibles en Internet pero ninguna de ellas ha funcionado, probablemente por utilizar el nombre de la BD en lugar del DSN.

String url = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=" + db + ";DriverID=22;READONLY=true";
String url = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=" + db;
String url = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb,*.accdb)};DBQ=" + db + ";DriverID=22;READONLY=true";
String url = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb,*.accdb)};DBQ=" + db;

Creo 2 sentencias SQL, una para saber el número total de registros con SELECT COUNT(Id) AS Contador FROM y otra para obtener los registros con SELECT * FROM. También creo 2 objetos ResulSet para contener lo que devuelve cada una de las sentencias. La interfaz ResultSet representa un conjunto de datos resultado de una consulta SQL, para acceder a los registros se emplea un cursor que inicialmente apunta antes del primer registro y para avanzar por los registros se emplea el método ResultSet.next. Con bucles while se itera por filas y columnas de la tabla de la BD para obtener sus valores que se van añadiendo como texto al control JTextArea. Con el método setCaretPosition(0) coloco el cursor de JTextArea siempre en la primera posición.

// consultas de seleccion SQL
Statement sql1 = con.createStatement();
Statement sql2 = con.createStatement();
ResultSet select1 = sql1.executeQuery("SELECT COUNT(Id) AS Contador FROM Tabla1");
// mientras ResultSet tenga registros
while (select1.next()) {
	// informar del numero de registros
	info.setText(ruta);
	bd.setText("Registros: " + select1.getInt("Contador"));
}

// ResultSet para almacenar registros devueltos por la consulta
ResultSet select2 = sql2.executeQuery("SELECT * FROM Tabla1 ORDER BY Id");
// mientras ResultSet tenga registros
while (select2.next()) 	{
	// rellenar JTextArea con los registros devueltos por la consulta
	String aux = new String (select2.getString("Id") + " - "); // mostrar la columna ID
	aux += select2.getString("Nombre") + " ("; // mostrar la columna Nombre
	aux += select2.getString("Telefono") + ")\n"; // mostrar la columna Telefono y salto de linea
	texto.append (aux); } // agregar lineas al control JTextArea
	texto.setCaretPosition(0); //cursor al principio del texto
	//texto.setCaretPosition(texto.getDocument().getLength()); //cursor al final del texto
}

Puedes descargar el código completo y la BD desde aquí.