java logoEl término metadata hace referencia a aquellas estructuras que definen / describen los campos de otras. Desde el punto de vista del programador, metadata se refiere a la información sobre los datos, mas concretamente, información sobre las tablas, columnas, nombres, resultsets, procedimientos almacenados y la propia bbdd.

En Java el API JDBC metadata proporciona acceso a esta información. Los metadatos son particularmente importantes cuando queremos escribir código que pueda adaptarse a varias bases de datos o contenido de las mismas. Esto implica que debemos descubrir las características de la bbdd en tiempo de ejecución, y adaptarnos a ella.

Uso de metadatos

El API Java de metadatos, como ya se ha comentado, puede emplearse para obtener la siguiente información de la bbdd:

  • Usuarios, tablas, vistas y procedimientos almacenados de la bbdd
  • Esquemas e información de catálogo
  • Privilegios de tablas, vistas y columnas
  • Información diversa sobre claves tanto primarias como foráneas.

Visión general JDBC

JDBC proporciona las APIs necesarias a los clientes para poder descubrir toda la información relacionada con metadatos relativa a la propia bbdd o bien a cualquier ResultSet empleando para ello las clases correspondientes.

metadata_api

El API contiene diversas interfaces que proporcionan la información de los metadatos al cliente. El cliente obtiene esta información vía JDBC Driver Manager. El Driver Manager actúa como un interface entre la bbdd y el API. Las bbdd propietarias proporcionan su propio driver Java (tipo 4). Por ejemplo, MySQL proporciona Connector/J; otras bases de datos, tales como Oracle o PostgreSQL, tienen su respectivo driver JDBC. En los casos en los que el proveedor de la bbdd no proporcione ningún driver se puede usar el puente JDBC/ODBC como intermediario entre el driver ODBC y el Driver Manager en Java. Para todos los casos el modo de obtener información sobre los metadatos es el mismo.

JDBC Metadata API

El API JDBC proporciona dos interfaces clave para obtener la información de los metadatos. DatabaseMetaData y ResultSetMetaData. Estas dos interfaces son parte del paquete java.sql. DatabaseMetaData se usa principalmente para recuperar información sobre la propia bbdd, tales como capacidades y estructura. Por otra parte, ResultSetMetaData, se usa para recuperar información sobre las propias consultas SQL tales como información sobre tamaños y tipos de columnas.

DatabaseMetaData

Este interface normalmente es implementado por el vendedor de la bbdd y proporcionado junto con el driver JDBC nativo.  Los drivers nativos, se sitúan justo encima de la bbdd, son la pieza de software más cercana a la bbdd en definitiva. Mediante la implementación de esta interfaz, los proveedores de bbdd proporcionan información comprensiva y explotable sobre la base de datos como un todo, nombres de tablas, índices, nombres de producto, versiones, etc. Existen unos cuantos métodos declarados en este interface para recuperar diversa información de los metadatos.

Ejemplo

package org.eloymp.example;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseMetaDataDemo {

   private static final String URL = "jdbc:mysql://localhost:3306/addressbook?zeroDateTimeBehavior=convertToNull";
   private static final String USERNAME = "testuser";
   private static final String PASSWORD = "secret";

   public static void main(String[] args) {
      Connection conn = null;
      DatabaseMetaData dbmd = null;
      try {
         conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
         dbmd = conn.getMetaData();
         if (dbmd != null) {
            System.out.println("Database Version: " + dbmd.getDatabaseProductVersion());
            System.out.println("Driver Name: " + dbmd.getDriverName());
            System.out.println("Driver Version: " + dbmd.getDriverVersion());
            System.out.println("URL: " + dbmd.getURL());
            System.out.println("User Name: " + dbmd.getUserName());
            System.out.println((dbmd.supportsANSI92FullSQL() ? "ANSI92FullSQL supported." : "ANSI92FullSQL not supported."));
            System.out.println((dbmd.supportsTransactions() ?"Transaction supported." :"Transaction not supported."));
         } else {
            System.out.println("Metadata not supported");
         }
      } catch (SQLException ex1) {
         System.err.println(ex1);
      } finally {
         try {
            conn.close();
         } catch (SQLException ex2) {}
      }
   }
}

ResultSetMetaData

Este interface proporciona información sobre la estructura de los objetos ResultSet, tales como número de columnas, nombre de las mismas, tipo y longitud, nombres de tablas, permisos de L/E sobre la columna, etc.

Ejemplo

package org.eloymp.example;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

public class ResultSetMetaDataDemo {

   private static final String URL ="jdbc:mysql://localhost:3306/addressbook?zeroDateTimeBehavior=convertToNull";
   private static final String USERNAME = "testuser";
   private static final String PASSWORD = "secret";
   private static final String SQL ="SELECT * FROM Addresses";

   public static void main(String[] args) {
      Connection conn = null;
      Statement stmt = null;
      ResultSet rs = null;
      ResultSetMetaData rsmd = null;

      try {
         conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
         stmt = conn.createStatement();
         rs = stmt.executeQuery(SQL);
         rsmd = rs.getMetaData();

         if (rsmd != null) {
            int cols = rsmd.getColumnCount();
            System.out.println("Number of Columns: " + cols);
            System.out.println("Table Name: " + rsmd.getTableName(1));
            System.out.println("Catalog Name: " + rsmd.getCatalogName(1));
            System.out.println ("------------------------------------------");
            for (int i = 1; i <= cols; i++) {
               System.out.println("Class Name: " + rsmd.getColumnClassName(i));
               System.out.println("Column Name: " + rsmd.getColumnName(i));
               System.out.println("Column Type Name: " + rsmd.getColumnTypeName(i));
               System.out.println ("--------------------------------------");
            }
         } else {
            System.out.println("ResultSetMetadata not supported");
         }

      } catch (SQLException ex1) {
         System.err.println(ex1);
      } finally {
         try {
            stmt.close();
            rs.close();
            conn.close();
         } catch (SQLException ex2) {}
      }
   }
}

ParameterMetaData

Estos objetos se emplean para recuperar información sobre los parámetros en los objetos PreparedStatement. Estos metadatos se refieren a los tipos y propiedades de los mismos tales como número, tipos, precisión, nombre de la clase Java asociada, etc

Ejemplo

package org.eloymp.example;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class ParameterMetaDataDemo {

   private static final String URL = "jdbc:mysql://localhost:3306/
      addressbook?zeroDateTimeBehavior=convertToNull";
   private static final String USERNAME = "testuser";
   private tatic final String PASSWORD = "secret";
   private static final String SQL = "SELECT id, firstName, lastName
      FROM Addresses WHERE id=? AND firstName LIKE ?";

   public static void main(String[] args) {

      Connection conn = null;
      PreparedStatement pstmt = null;
      ParameterMetaData pmd = null;

      try {
         conn = DriverManager.getConnection(URL,
            USERNAME, PASSWORD);
         pstmt = conn.prepareStatement(SQL);
         pmd = pstmt.getParameterMetaData();
         if (pmd != null) {
            System.out.println("Parameter Count: " + pmd.getParameterCount());
         } else {
            System.out.println("ParameterMetadata not supported by the database");
         }
      catch (SQLException ex1) {
         System.err.println(ex1);
      } finally {
         try {
            pstmt.close();
            conn.close();
         } catch (SQLException ex2) {

         }
      }
   }
}

RowSetMetaData

El interfaz RowSetMetaData forma parte del paquete javax.sql y se corresponde con una sub-implementación del interfaz ResultSetMetaData.Esta clase proporciona información sobre las columnas en un objeto RowSet, tales como qué columnas contiene y sus tipos.

Ejemplo

package org.eloymp.example;

import java.sql.SQLException;
import javax.sql.RowSetMetaData;
import javax.sql.rowset.WebRowSet;
import com.sun.rowset.WebRowSetImpl;

public class RowSetMetaDataDemo {

   private static final String URL = "jdbc:mysql://localhost:3306/addressbook?zeroDateTimeBehavior=convertToNull";
   private static final String USERNAME = "testuser";
   private static final String PASSWORD = "secret";
   private static final String SQL = "SELECT * FROM Addresses";

   public static void main(String[] args) {
      WebRowSet rowSet = null;
      RowSetMetaData rsmd = null;

      try {
         Class.forName("com.mysql.jdbc.Driver");
         rowSet = new WebRowSetImpl();
         rowSet.setUrl(URL);
         rowSet.setUsername(USERNAME);
         rowSet.setPassword(PASSWORD);
         rowSet.setCommand(SQL);
         rowSet.execute();

         rsmd = (RowSetMetaData) rowSet.getMetaData();
         if (rsmd != null) {

            int count = rsmd.getColumnCount();
            for (int i = 1; i <= count; i++)
               System.out.println("Column Name: " +rsmd.getColumnName(i) +" Type: " + rsmd.getColumnTypeName(i));
         } else {
            System.out.println("RowSetMetadata not supported");
         }
      } catch (ClassNotFoundException | SQLException ex1) {
         System.err.println(ex1);
      } finally {
         try {
            rowSet.close();
         } catch (SQLException ex2) {

         }
      }
   }
}

Conclusión

Los ejemplos aquí presentados son simplemente un punto de inicio experimental con las API’s JDBC de metadatos. Estas API’s son indispensables para la mayoría de aplicaciones relacionadas con bbdd. Son particularmente interesantes para crear soluciones relacionadas con bbdd personalizadas o bien navegadores de información en modo gráfico. Por ejemplo, podríamos crear un frontal dinámico basado en las estructuras de las tablas obtenidas a partir de los metadatos de las mismas. Para más información consultar la documentación existente a respecto de Oracle.

Un saludo a todos y hasta la próxima.

You must be logged in to post a comment.