SlideShare ist ein Scribd-Unternehmen logo
1 von 23
Downloaden Sie, um offline zu lesen
Manejar Conexiones a
 Bases de Datos con
     JDBC 3.0
Manejar Conexiones a Bases de Datos con JDBC 3.0




Introdución al Tutorial

¿Debería leer este Tutorial?
Este tutorial presenta los diferentes conceptos implicados en el establecimiento y control de una
conexión con bases de datos dentro de una aplicación Java usando Java Database Connection
(JDBC). Está dirigido principalmente a desarrolladores que quieren entender que "qué hay
detrás de la escena" cuando usan una base de datos desde dentro de una aplicación Java
Este tutorial asume que estás familiarizado con el lenguaje de programación Java.

¿Sobre qué va este Tutorial?
Este tutorial demuestra cómo conectar con una base de datos usando JDBC. Aunque parece
inocuo, este punto es realmente un obstáculo tanto para novatos como para veteranos en Java.
Este tutorial explicará cómo una aplicación Java dentro de una JVM descubre y se comunica con
una base de datos, empezando con el tradicional driver JDBC y los objetos DriverManager.
Después de varios ejemplos que demuestran los cuatro tipos diferentes de drivers JDBC, el
tutorial se mueve sobre una explicación de objetos DataSource que usan JNDI. También se
incluye una discusión sobre JNDI, y cómo unir, usar, reunir y borrar el objeto DataSource.
Finalmente, se presentan y demuestran los conceptos de almacen de conexiones, y
específicamente los objetos PooledConnection. El tutorial concluye con una discusión de
problemas de ajuste que normalmente se nos pasan cuando desarrollamos aplicaciones de
conectividad de base de datos.

Herramientas
Aunque el tutorial proporciona numerosos fragmentos de código para reflejar conceptos y
métodos descritos en el texto, la mayoría de la gente aprenderá mejor trabajando realmente a
través de los ejemplos. Para trabajar con los ejemplos, necesitarás tener instaladas y
funcionando las siguientes herramientas:
Un editor de texto: los ficheros fuente Java son simplemente texto, por eso para crearlos y
leerlos, necesitamos un editor de texto. Si tienen acceso a un IDE Java, puedes usarlo, pero
algunas veces ocultan muchos detalles.
Un entorno de desarrollo Java, como el Java2 SDK, que está disponible en
http://java.sun.com/j2se/1.4/. El Java2 SDK, Standard Edition versión 1.4, incluye las
extensiones estándard JDBC así como JNDI, ámbos son necesarios para algunos de los
ejemplos posteriores de este tutorial
Una base de datos compatible SQL: los ejemplos de este tutorial usan una amplia variedad de
bases de datos para ayudarnos a demostrar cómo se puede hacer programación JDBC
independiente de la base de datos.
Un driver JDBC: como el API JDBC está predominantemente compuesto por interfaces,
necesitamos obtener una implementación de un driver JDBC real para poder conectar
realmente con una base de datos usando JDBC. Si nuestra base de datos (o nuestra maleta) no
permite el uso de JDBC, siempre podemos usar el dirver puente JDBC-ODBC para conectar con
cualquier base de datos (o fuente de datos) que soporta el protocolo ODBC.




                                          Página 2 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Arquitectura de la Aplicación

Arquitecturar Nuestro Sistema
Uno de los problemas de diseño más importantes cuando desarrollamos una aplicación de
bases de datos en Java es la arquitectura general del sistema; en particular, cuántos
componentes diferentes deberíamos desplegar. Tradicinonalmente, esto está caracterízado por
el número de capas que requiere la aplicación. Hay dos modelos arquitecturales básicos que
pueden describir un sistema: el modelo de dos capas y el modelo de n-capas.
Antes de entrar en los detalles del manejo de conexiones a bases de datos desde una aplicación
Java, necesitamos explicar estos dos modelos. Cada modelo tiene sus propias ventajas e
inconvenientes; cada uno también requiere que ciertos componentes se configuren
apropiadamente, y , como resultado, cada uno funciona mejor en entornos diferentes. Las dos
siguientes secciones explican en más detalle cada uno de los dos modelos arquitecturales.

El Modelo de Dos Capas
El modelo de dos capas es el marco de trabajo tradicional cliente-servidor; tiene una capa
cliente y una capa servidor. Este modelo simple requiere que el cliente tenga cuidado específico
de la base de datos. Así, por ejemplo, el cliente necesita código específico de la base de datos
resultando en un acoplamiento fuerte entre las dos capas. Este acoplamiento fuerte tienes
varias ventajas. Primero, puede reducir el tiempo de desarrollo debido al hecho de que todo el
sistema es considerablemente más simple y más pequeño. Segundo, el acoplamiento fuerte
puede mejorar potencialmente el rendimiento del sistema ya que el cliente puede fácilmente
aprovecharse de las funcionalidades específicas del servidor que podrían no estar disponibles
para sistemas con un acoplamiento más ligero.
Por otro lado, este acoplamiento fuerte puede provocar varios problemas. El mas notable, el
mantenimiento del sistema se puede volver más díficil porque los cambios en el servidor
pueden romper al cliente y viceversa. Además, si la base de datos cambia, todo el código del
cliente deberá ser modificado. Si el cliente está altamente distribuido, la propagación de los
cambios en el sistema puede ser díficil, y en algunos escenarios imposible. Como resultado, las
aplicaciones de dos capas pueden ser útiles en un entorno de LAN corporativa donde el
completo control de todos los clientes se consigue, o al inicio, o en el estado prototipal de un
proyecto donde diferentes opciones están siendo evaluadas.

El Modelo de n-Capas
El modelo de n-capas tiene una capa cliente, al menos una capa servidor, y al menos una cada
intermedia. Debido a la capa extra, muchos de los problemas que afectan a los modelos de dos
capas no afectarán. Por ejemplo, la capa media ahora mentiene información de la conexión a la
base de datos. Esto significa que los clientes sólo tienen que conocer la capa media. Como la
capa media generalmente está operando en la misma localización física que el servidor (por
ejemplo, ambos componentes pueden estar detrás del mismo firewall), mantener la capa media
es considerablemente más sencillo que mantener cientos de instalaciones clientes.
Otra ventaja de la aproximación de n-capas es que todo el sistema se puede escalar fácilmente
para manejar más usuarios.Todo lo que necesitamos hacer es añadir más capas medias o más
capas servidores, dependiendo de los resultados de las operaciones de perfilado. Como las
capas intermedias normalmente se implementan usado servidores Web -- usando tecnologías
JavaServer Pages y Servlets -- es muy sencillo añadir balance de carga o incluso nuevos
componentes hardware.
Sin embargo, no todo es de color rosa, ya que la capa extra intoduce complejidad adicional en
todo el sistema. Esto significa más código, más duro de probar y potencialmente más díficil de
encontrar sus errores. Afortunadamente, el lenguaje Java proporciona muchos de los
componentes necesarios, pre-construidos. para construir aplicaciones de n-capas viables.
Además, este modelo se presta a si mismo el fácil soporte de autentificación e
internacionalización, ya que la capa media controla el flujo de información y proporciona
localización natural para manjear todo lo que concierne al manejo de seguridad y la
localización.




                                          Página 3 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Fundamentos de los Drivers JDBC

Introducción a los Drivers JDBC
Una inspección casual del API JDBC muestra rápidamente la dominación de los interfaces
dentro del API, lo que podría llevar al usuario a preguntarse dónde se realiza el trabajo.
Realmente esta es sólo una aproximación que tocan los desarrolladores JDBC porque la
implementación real es la proporcionada por los vendedores de Drivers JDBC, que a su vez
proporcionan las clases que implementan los interfaces necesarios. Esta aproximación presenta
la competición que proporciona al consumidor más opciones, y para la mayor parte, produce
mejor software. Con todos los drivers disponibles. elegir uno puede ser díficil.
Aforturnadamente, Sun Microsystems mantiene una base de datos con más de 150 drivers
JDBC de una amplia variedad de vendedores. Esta debería ser la primera parada después de
seleccionar una base de datos.
Desde una perspectiva de programación, hay dos clases principales respnsables para el
establecimiento de una conexión con una base de datos. La primera clase es DriverManager,
que es una de las clases que realmente proprociona el API JDBC. DriverManager es responsable
de manejar un almacen de drivers registrados, esencialmente abstrayendo los detalles del uso
de un driver para que el programador no tenga que tratar con ellos directamente. La segunda
clase es la clase real del Driver JDBC. Estas son proporcionadas por vendedores independientes.
La clase Driver JDBC es la responsable de establecer la conexión con la base de datos y de
manejar todas las comunicaciones con la base de datos. Los drivers JDBC vienen en cuatro
tipos diferentes

Registrar un Driver JDBC
El primer paso en el proceso de crear una conexión entre una aplicación Java y una base de
datos es el registro de un driver JDBC con la Máquina Virtual Java (JVM) en la que se está
ejecutando la aplicación Java. En el mecanimso de conexión tradicional (en oposición al
mecanismo de conexión del DataSource) la conexión y todas las comunicación con la base de
datos son controladas por un objeto DriverManager. Para establecer una conexión, se debe
registrar un driver JDBC adecuado para la base de datos objetivo con el objeto DriverManager.
La especificación JDBC, dice que se supone que los dirvers JDBC se registran automáticamente
a sí mismos con el objeto DriverManager cuando se cargan en la JVM. Por ejemplo, el siguiente
fragmento de código usa un inicializador estático para primero crear un ejemplar del driver
JDBC persistentjava y luego resgistrarlo con el DriverManager:
static {
  java.sql.DriverManager.registerDriver(new com.persistentjava.JdbcDriver()) ;
}
Registrar un driver es tan simple como cargar la clase del driver en la JVM, lo que puede
hacerse     de     muchas      maneras.      Una     forma       es      con     el    ClassLoader
Class.forName(com.persistentjava.JdbcDriver). Otro método, que no es tan bien
conocido, usa la propidad del sistema jdbc.drivers. Este método se puede usar de tres formas
distintas:
Desde la línea de comandos:
java -Djdbc.drivers=com.persistentjava.JdbcDriver Connect
Dentro de la palicación Java:
System.setProperty("jdbc.drivers","com.persistentjava.JdbcDriver") ;
Seleccionando la propiedad jdbc.drivers en el fichero de propiedades del sistema, que
generalmente depende del sistema.
Separando los drivers con una coma, se pueden registrar varios drivers usando la técnica de la
propiedad del sistema mostrada arriba. Uno de los beneficios de usar la técnica de la propiedad
del sistema es que se los drivers se pueden intercambiar fácilmente sin modificar ningún código
(o al menos con unos mínimos cambios). Si se registran varios drivers, su orden de precedencia
es:
Drivers JDBC registrados por la propiedad jdbc.drivers en la inicialización de la JVM, y
Drivers JDBC cargados dinámicamente.




                                          Página 4 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Como la propiedad jdbc.drivers sólo se chequea una vez durante la primera invocación del
método DriverManager(), es importante asegurarse de que todos los drivers están registrados
correctamente antes de establecer la conexión con la base de datos. Sin embargo, no todas las
JVM están creadas igual, y algunas de ellas no siguen la especificación JVM. Como resultado,
los inicializadores estáticos no siempre funcionan como hemos dibujado. Esto resulta en
múltiples formas de registrar un driver JDBC, incluyendo:
Class.forName("com.persistentjava.JdbcDriver").newInstance();
DriverManager.registerDriver(new com.persistentjava.JdbcDriver()) ;
Estas alternativas deberían funcionar bien en todas las JVMs, por eso deberíamos sentirnos
agusto usándolas a lo largo del amplio conjunto de JVM disponibles. Un problema final es que
Class.forname() puede lanzar una ClassNotFoundException, por eso debemos envolver el
código de registro en un manejador de excepción apropiado.

URLs de Drivers JDBC
Una vez que un Driver JDBC se ha registrado con el DriverManager, puede usarse para
establecer una conexión a una base de datos. ¿Pero cómo selecciona DriverManager el driver
correcto, dado que puede haber realmente rigstrados cualquier número de drivers? (Recuerda,
una sóla JVM podría soportar múltiples aplicaciones concurrentes, que podrían conectarse con
diferentes bases de datos con diferentes drivers). La técnica es bastante simple: cada driver
JDBC usa una URL JDBC específica (que tiene el mismo formato que una dirección Web) como
un significado de auto-identificación. El formato de la URL es correcto y probablemente parece
familiar: jdbc:sub-protocol:database locator. El sub-protocol es específico del driver JDBC y
puede ser odbc, oracle, db2, etc., dependiendo del vendedor del driver real. El localizador de
la base de datos es un indicador específico del driver para específicar de forma única la base de
datos con la que una aplicación quiere interactúar. Dependiendo del tipo de driver, este
localizador incluye un nombre de host, un puerto, y un nombre de sistema de base de datos.
Cuando se presenta con una URL específica, el DriverManager itera sobre la colección de
drivers registrados hasta que uno de ellos reconoce la URL específicada. Si no se encuentra
ningún driver adecuado, se lanza una SQLException. La siguiente lista presenta varios ejemplos
específicos de URLs JDBC reales:
jdbc:odbc:jdbc

jdbc:oracle:thin:@persistentjava.com:1521:jdbc";

jdbc:db2:jdbc
Muchos drivers, incluyendo el driver puente JDBC-ODBC, acepta parámetros adicionales al
final de la URL como un nombre de usuario y una password.
El método para obtener una conexión a una base de datos, dando una URL JDBC específica, es
llamar a getConnection() sobre el objeto DriverManager. Este método tiene varias formas:
DriverManager.getConnection(url) ;

DriverManager.getConnection(url, username, password) ;

DriverManager.getConnection(url, dbproperties) ;
Aquí url es un objeto String que es la URL JDBC, username y password son objetos String que
representan el nombre de usuario y la password que la aplicación JDBC debería usar para
conectar con la fuente de datos; y dbproperties es un objeto Properties de Java que encapsula
todos los parámetros (posiblemente incluyendo nombre de usuario y la password) que requiere
un driver JDBC para hacer una conexión con éxito. Ahora que tenemos el driver básico en la
mano, podemos examinar los tipos de drivers individuales con más detalle:




                                          Página 5 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Drivers del Tipo 1




Los drivers del tipo uno tienen algo en común: todos usan el puente JDBC-ODBC, que está
incluido como parte estándard del JDK. Los drivers del tipo uno son diferentes al driver ODBC
(Open DataBase Connectivity) adjunto al puente JDBC-ODBC. Para conectar con una fuente
de datos diferente, simplemente tenemos que registrar (o unir efectivamente) una fuente de
datos ODBC diferente, usando el Administrador ODBC, al nombre de la fuente de datos
apropiada.
Como ODBC se ha estado utilizando desde hace bastante tiempo (más que el lenguaje Java),
los drivers ODBC son ubicuos. Esto hace de este tipo de drivers una buena elección para
aprender cómo conectar programas Java a bases de datos. De hecho, incluso hay drivers ODBC
que nos permiten asignar fuentes de datos ODBC a una aplicación Microsoft Excel o ficheros de
texto plano. Sin embargo, el nivel extra de indirección, puede resultar en una pérdida de
rendimiento ya que el JDBC es transferido dentro de ODBC, que luego es transferido en el
protocolo específico de la base de datos.
Otro problema potencial de los drivers del tipo uno es su utilización en aplicaciones distribuidas.
Como el propio puente no soporta comunicación distribuida, la única forma de que los drivers
del tipo uno puedan trabajar a través de la red es si el propio driver ODBC soporta interacción
remota. Para drivers ODBC sencillos, esta no es una opción, y mientras que las grandes bases
de datos tienen drivers ODBC que pueden trabajar de forma remota, no pueden competir con el
mejor rendimiento de los drivers JDBC puro Java.




                                           Página 6 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Codificación para Drivers del Tipo 1

El nombre de clase para el driver puente JDBC-ODBC es sun.jdbc.odbc.JdbcOdbcDriver y al
URL JDBC toma la forma jdbc:odbc:dsn, donde dsn es el Data Source Name (nombre de la
fuente de datos) usado para registrar la base de datos con el Administrador ADBC. Por ejemplo,
si una base de datos se registra con una fuente de datos ODBC llamada jdbc; un nombre de
usuario de java y una password de sun, se puede usar el siguiente fragmento de código para
establecer una conexión.

     Nota:
     En interés de la claridad y la brevedad, se ha eliminado del listado el chequeo y
     manejo de errores. Posteriores ejemplos, demostrarán la importancia de estos
     mecanismos (específicamente, la captura de errores encadenando sentencias
     SQLException).

String url = "jdbc:odbc:jdbc" ;
Connection con ;
try {
    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ;
} catch(java.lang.ClassNotFoundException e) {
    System.err.print("ClassNotFoundException: ") ;
    System.err.println(e.getMessage()) ;
    return ;
}
try {
    con = DriverManager.getConnection(url, "java", "sun");
} catch(SQLException ex) {
    System.err.println("SQLException: " + ex.getMessage());
} finally {
    try{
         con.close ;
    } catch(SQLException ex) {
    System.err.println(SQLException: " + ex.getMessage()) ;
    }
}




                                         Página 7 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Drivers del Tipo 2




Los drivers del tipo dos también son conocidos como drivers Java parciales, porque traducen
directamente el API JDBC en un API específico de la base de datos. La aplicación cliente de
base de datos (para el propóstio de este tutorial, el host que está ejecutando la JVM) debe
tener las librerías cliente apropiadas para la base de datos, que podrían incluir código binario
instalado y posiblemente ejecutándose. Para una aplicación distribuida, este requerimietno
puede introducir problemas extra con las licencias, así como posibles pesadillas con los
problemas de distribución de código. Por ejemplo, usar un modelo del tipo dos restringe a los
desarrolladores a utilizar plataformas y sistemas operativos soportados por la librería cliente de
la base de datos.
Sin embargo, este modelo puede funcionar eficientemente, cuando la base cliente está
fuertemente controlada.. Esto ocurre típicamente en LANs corporativas. Un ejemplo de driver
del tipo dos es el driver de aplicación JDBC para DB2. El siguiente ejemplo demuestra cómo
establecer una conexión usando un driver DB2:
String url = "jdbc:db2:jdbc" ;
try {
      Class.forName("COM.ibm.db2.jdbc.app.DB2Driver") ;
} catch(java.lang.ClassNotFoundException e) {
      System.err.print("ClassNotFoundException: ") ;
      System.err.println(e.getMessage()) ;
      return ;
}
...
Observa la similitud que tiene este fragmento de código con el del ejemplo 1. Esta es la
principal característica del modelo del tipo 2: la curva de aprendizaje para un programador que
se mueve de un modelo a otro es prácticamente inexistente.
Los dos últimos tipos de drivers son drivers puro Java. El beneficio de los drivers puro Java es
su fácil despliegue en entonos altamente distribuidos.




                                          Página 8 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Drivers del Tipo 3




Los drivers del tipo tres son drivers puro Java que transforman el API JDBC en un protocolo
independiente de la base de datos. El driver JDBC no comunica directamente con la base de
datos; comunica con un servidor de capa media, que a su vez comunica con la base de datos.
Este nivel extra de indirección proporciona flexibilidad en que se puede acceder a diferentes
bases de datos desde el mismo código porque el servidor de la capa media oculta las
especificidades a la aplicación Java. Para cambiar a una base de datos diferente, sólo
necesitamos cambiar los parámetros en el servidor de la capa media. (Un punto a observar: el
formato de la base de datos a la que estamos accediendo debe ser soportado por el servidor de
la capa media).
El lado negativo de los drivers del tipo tres es que el nivel extra de indirección puede perjudicar
el rendimiento general del sistema. Por otro lado, si una aplicación necesita interactúar con una
variedad de formatos de bases de datos, un driver del tipo tres en una aproximación adecuada
debido al hecho de que se usa el mismo driver JDBC sin importar la base de datos subyacente.
Además, como el servidor de la capa media se puede instalar sobre una plataforma hardware
específica, se pueden realizar ciertas optimizaciones para capitalizar los resultados perfilados.




                                           Página 9 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Drivers del Tipo 4




Los drivers del tipo cuatro son drivers puro Java que se comunican directamente con la base de
datos. Muchos programadores consideran éste el mejor tipo de driver, ya que normalmente
proporciona un rendimiento óptimo y permite al desarrollador utilizar las funcionalidades
específicas de la base de datos. Por supuesto este acoplamiento puede reducir la flexibilidad,
especialmente si necesitamos cambiar la base de datos subyacente en una aplicación. Este tipo
de driver se usa frecuentemente en applets y otras aplicaciones altamente distribuidas. El
siguiente fragmento de código muestra cómo usar un driver DB2 del tipo cuatro:
String url = "jdbc:db2://persistentjava.com:50000/jdbc" ;
try {
      Class.forName("COM.ibm.db2.jdbc.net.DB2Driver") ;
} catch(java.lang.ClassNotFoundException e) {
      System.err.print("ClassNotFoundException: ") ;
      System.err.println(e.getMessage()) ;
      return ;
}
...




                                        Página 10 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Un Ejemplo Completo de Driver del Tipo 4

El siguiente ejemplo muestra cómo usar un driver JDBC de un vendedor de terceras partes, en
este caso Merant, para conectar con una base de datos DB2. DB2 UDB requiere información
adicional, no estándard para establecer la conexión a la base de datos, que en este ejemplo
están añadidos a la URL JDBC como parámetros opcionales.

package com.persistentjava;
import java.sql.*;

public class ConnectMerantDB2 {
    static {
        try {
             Class.forName("com.merant.datadirect.jdbc.db2.DB2Driver").newInsta
nce();
        } catch (Exception e) {
        System.out.println(e);
        }
    }

public static void main(String args[]) {
        String url = "jdbc:merant:db2://persistentjava.com:50000;" ;
        url += "DatabaseName=jdbc;CollectionId=DEFAULT;" ;
        url += "PackageName=JDBCPKG;CreateDefaultPackage=TRUE";
        Connection con;
        System.out.println("Connecting");
        try {
            con = DriverManager.getConnection(url, "java", "sun");
            System.out.println("Connection Established");
            con.close();

             // In this example, the proper handling of SQLExceptions is
             // demonstrated as they can be potentially chained.
         } catch (SQLException e) {
             System.out.println("nERROR:----- SQLException -----n");
             while (e != null) {
                 System.out.println("Message: " + e.getMessage());
                 System.out.println("SQLState: " + e.getSQLState());
                 System.out.println("ErrorCode: " + e.getErrorCode());
                 e.printStackTrace();
                 e = e.getNextException();
             }
         }
    }
}




                                       Página 11 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Transaciones con Bases de Datos

Transaciones Básicas
Uno concepto que causa problemas a los principiantes en el mundo del desarrollo de
aplicaciones de base de datos es la idea de transaciones. Fundamentalmente, una transación
representa una unidad de trabajo lógica. Como la principal responsabilidad de una base de
datos es preservar la información, necesita tener algo que le indique a un usuario que se debe
salvar el estado actual del programa. De igual forma, cuando las cosas han ido mal, necesita
una forma para indicar que una base de datos deberia ignorar el estado actual y volver a atrás,
al estado del programa salvado anteriormente.
En el idioma de las bases de datos, estas funciones se llaman entregar una transación y
deshacer una transación, respectivamente. Para realizar estas tareas, el API JDBC incluye
dos métodos como parte del interface Connection. Dando un objeto Connection llamado con, el
estado del programa se graba llamando a con.commit(), para volver al estado salvado
anteriormente, con.rollback(). Estos dos métodos pueden lanzar SQLExceptions si algo va
mal cuando la base de datos realice realmente la operación, por eso necesitamos envolverlos
en bloques try ... catch.

Más sobre Transaciones
En un entorno mono-usuairo, las transaciones son bastantes sencillas de entender --
simplemente implican salvar o deshacer el estado de una aplicación. Sin embargo, en modo
multi-usuario, las transaciones son más complejas. La demostración clásica de una transación
multi-usuario es una cuenta bancaria donde una aplicación está intentando hacer un cargo
mientras otra aplicación está intentando hacer un depósito en la misma cuenta. Si estas
familiarizado con la programación concurrente (también conocida como programación multi-
thread), probablemente hayas visto este problema antes. El problema fundamental es que a
menos que las dos transaciones estén aisladas la una de la otra, una aplicación podría
interrumpir a la otra resultando en un estado del programa incorrecto. En nuestra sencilla
demostración, esto podría significar una cuenta con un saldo erróneo, algo que no es
precisamente bueno para retener clientes.
Pueden aparecer tres problemas comunes cuando tratamos con varios usuarios que acceden a
los mismos datos:
Lecturas sucias. Un lectura sucia ocurre cuando una aplicación usa datos que han sido
modificados por otra aplicación, y esos datos están en un estado sin entregar. La segunda
aplicación entonces solicita que los datos que fueron modificados sean desechos. Entonces los
datos de la primera transación están corruptos o "sucios".
Lecturas no-repetibles. Una lectura no-repetible ocurre cuando una transación obtiene
datos, que posteriormente son alterados por una transación separada, y la primera transación
re-lee los datos ahora alterados. Así, la primera transación hizo una lectura no-repetible.
Lecturas fantasmas. Una lectura fantasma ocurre cuando una transación adquiere datos
mediante alguna consulta, otra transación modifica algunos de los datos, y la transación original
recupera los datos una segunda vez. La primera transación ahora tendrá un conjunto de
resultados diferentes, que podrían contener datos fantasmas.
Niveles de Transación
Para resolver los problemas asociados a múltiples threads solicitando los mismos datos, las
transaciones están aisladas unas de otras por bloqueos. La mayoría de las bases de datos
soportan diferentes tipos de bloqueo; por lo tanto, el API JDBC soporta diferentes tipos de
transaciones, que son asignadas o determinadas por el objeto Connection. En el API JDBC tiene
disponibles los siguientes niveles de transaciones:
TRANSACTION_NONE indica que las transaciones no están soportadas.
TRANSACTION_READ_UNCOMMITTED indica que una transación puede ver los cambios de otra
transación antes de ser entregada. Así están permitidas las lecturas sucias, las lecturas no-
repetibles, y las lecturas fantasmas.




                                         Página 12 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




TRANSACTION_READ_COMMITTED indica que la lectura de datos no entregados, no está
permitida. Este nivel todavía permite que ocurran las lecturas no-repetibles y las lecturas
fantasmas.
TRANSACTION_REPEATABLE_READ indica que una transación está garantizada que pueda re-
leer el mismo dato sin fallar, pero las lecturas fantasmas todavía pueden ocurrir.
TRANSACTION_SERIALIZABLE es la transación de más alto nivel y evita que ocurran las
lecturas sucias, las lecturas no-repetibles y las lecturas fantasmas. Podríamos preguntarnos
porqué todas las transaciones no operan en modo TRANSACTION_SERIALIZABLE para
garantizar el grado más alto de integridad de datos. El problema es, de forma similar a los
problemas implicados con el manejo de la programación de múltiples threads, que cuanto más
sea el nivel de protección de transación, más alta será la pérdida de rendimiento.
Dando un objeto Connection podemos seleccionar explícitamente el nivel de transación,
asumiendo que nuestra base de datos y nuestro driver JDBC soporten esta característica:
con.setTransactionLevel(TRANSACTION_SERIALIZABLE) ;
También podemos determinar el nivel de transación actual:
if(con.getTransactionLevel() == TRANSACTION_SERIALIZABLE)
         System.out.println("Highest Transaction Level in operation.") ;

Lotes y Transaciones
Por defecto, los drivers JDBC operan en lo que se llama modo autoentrega. En este modo,
todos los comandos enviados a la base de datos operan en su propia transación. Aunque esto
puede ser útil para los principiantes, implica una pérdida de rendimiento porque las
transaciones requieren una cierta cantidad de sobrecarga para configurar todo apropiadamente.
Si queremos poder controlar explícitamente las entregas y los retrocesos (deshacer la
transación), necesitamos desactivar el modo autocommit:
con.setAutoCommit(false) ;

También podemos determinar rápidamente el modo autocommit de un objeto Connection dado:
if(con.getAutoCommit() == true)
      System.out.println("Auto Commit mode");
Muchas bases de datos soportan lotes, en los que se minimiza la sobrecarga de transaciones
realizando múltiples operaciones update de la base de datos en una sóla operación, o lote. Las
operaciones por lotes fueron introducidas en JDBC 2.0 y requieren que una transación no esté
en modo autocommit. En el siguiente ejemplo tenemos una operación por lotes, que asume que
existe una Connection a una base de datos que tiene una sola tabla:
con.setAutoCommit(false) ;
Statement stmt = connection.createStatement() ;
stmt.addBatch("INSERT INTO people VALUES('Joe Jackson', 0.325, 25, 105) ;
stmt.addBatch("INSERT INTO people VALUES('Jim Jackson', 0.349, 18, 99) ;
stmt.addBatch("INSERT INTO people VALUES('Jack Jackson', 0.295, 15, 84) ;
int[] updateCounts = stmt.executeBatch() ;
con.commit() ;
Observa que el método executeBatch() devuelve un array de cuentas actualizadas, una por
cada operación del lote. Un último problema con las operaciones por lotes es que pueden lanzar
una nueva excepción del tipo BatchUpdateException, lo que indica que falló al menos uno de
los comandos del lote. Por eso, necesitamos añadir un manejador de excepciones
correspondiente a nuestras operaciones por lotes.
Control Fino de las Transaciones
Empezando con el API JDBC 3.0, se añadió un nuevo elemento interface relacionado con las
transaciones. Este interface presenta el concepto de savepoints. Los Savepoints proporcionan
un marca dentro de una aplicación de base de datos que puede usarse como un argumento
cuando se llama al método rollback. Como resultado, usando el API JDBC 3.0, ahora es posible
seleccionar un savepoint antes de empezar una interacción complicada con la base de datos y,
dependiendo del resultado, entregar la transación completa o deshacer hasta el savepoint y
devolver la aplicación a un punto conocido.




                                        Página 13 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Para seleccionar un punto de salvado, creamos un objeto Savepoint desde el objeto
Connection, como se ve aquí:
Savepoint svpt = con.setSavepoint("Savepoint") ;
Para deshacer hasta un Savepoint dado, simplemente le pasamos el objeto Savepoint deseado
al método rollback:
con.rollback(svpt) ;
Cuando no se necesitan más, liberamos todos los objetos Savepoint para liberar los caros
recursos de la base de datos para otros usuarios:
con.releaseSavepoint(svpt) ;
Observa que cuando entregamos o deshacemos una transación, cualquier Savepoints creado
podría convertirse en inválido dependiendo del orden exacto y del tipo de operación. Puedes
ver la especificación del API JDBC 3.0 o el manual de tu driver para más información.




                                       Página 14 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Fuentes de Datos

Fuentes de Datos Básicas
Uno de los principales benficios de usar el API JDBC es facilitar una programación
independiente de la base de datos, así la mayoría de las aplicaciones JDBC pueden transferirse
fácilmente a otra base de datos diferente. Sin embargo, todavía hay dos ítems que permacenen
unidos a una base de datos particular, la clase JDBC Driver y la URL JDBC. Con la introdución
de las fuentes de datos en el API JDBC 2.0, se eliminaron incluso estas dependencias.
Esencialmente un objeto DataSource representa una fuente de datos particular en una
aplicación Java. Además de encapsular la información específica de la base de datos y del driver
JDBC en un sólo objeto estándarizado, las fuentes de datos pueden actuar como una factoría
de Connection y proporcionar métodos para seleccionar y obtener propiedades particulares que
requiere el objeto DataSource para una operación satisfactoria. Algunas propiedades estándar
que podría requerir un objeto DataSource incluyen:
         ·databaseName
         ·serverName
         ·portNumber
         ·userName
         ·password
Un beneficio adicional de usar una DataSource, que podrías haber adivinado de la lista anterior,
es que la información sensible relacionada con la seguridad como el nombre de usuario, la
password, e incluso el servidor de la base de datos están códificados sólo en un lugar, lo que
puede hacer un administrador de sistemas. Mientras que la interacción con un objeto
DataSource se puede hacer con una aplicación gráfica, es instructivo ver como trabajan
realmente los ejemplos. Aunque los conceptos de un objeto DataSource son bastantes simples,
para usarlo dentro de una aplicación Java, un objeto DataSource es referenciado usando Java
Naming and Directory Interface, o JNDI. Antes de saltar dentro del código de ejemplo de
DataSource, el siguiente punto presenta conceptos relevantes de JNDI que son necesarios para
usar apropiadamente un objeto DataSource.

Repaso Rápido de JNDI
JNDI es un API Java que encapsula el concepto de servidores de nombres y directorios de la
misma forma que JDBC encapsula los conceptos que hay detrás de la comunicación con una
base de datos. Aunque podría parecer confuso, es bastante sencillo -- todos lo usuarios de
ordenadores usan servicios de nombres y directorios todos los días. Por ejempo, los discos
duros trabajan con pistas y sectores, aunque un usuario sólo se preocupa de nombres de
ficheros y directorios. El sistema de ficheros maneja el servicio de nombrado que asocia un
nombre de fichero dado con una localización específica en el disco duro. Otro ejemplo es la
Web, donde la mayoría de los usuarios sólo se preocupan del nombre de la Web site, como
www.persistentjava.com, y no de la dirección IP subyacente. Sin embargo, la comunicación
TCP/IP se hace usando la dirección IP y no usando el nombre que leemos los humanos. La
transformación entre las dos representaciones la realiza el DNS, o Domain Name System.
Aunque JDNI proporciona un API ámplio y útil por sí mismo, nuestras necesidades son
considerablemente simples. En breve, necesitamos conocer como hacer cuatro cosas:
        ·Crear un nombre y unirlo a un objeto Java.
        ·Buscar un nombre para recuperar un objeto Java.
        ·Borrar un nombre.
        ·Re-unir un nombre a nuevo objeto Java.
En vez de proporcionar ejemplos JNDI imaginarios para las tareas anteriores, las siguientes
secciones muestran ejemplos de estas tareas usando fuentes de datos JDBC. Todos estos
ejemplos usan el proveedor de sistema de ficheros, que es una descarga separada.




                                         Página 15 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Registrar una Fuente de Datos
Este ejemplo es una implementación de un DataSource de tereceras partes de i-net software
para conectar con una base de datos MS SQL Server. Los comentarios en el código marcan los
puntos importantes de registro (o inicialziación) de una fuente de datos JDBC:
// We need to import the actual DataSource implementation
import com.inet.tds.TdsDataSource;
import java.util.Hashtable;
import javax.naming.*;
import javax.naming.directory.*;
import java.sql.* ;
import javax.sql.* ;
public class InitializeJNDI {
    // First we define the relevant parameters for this datasource
    private String serverName = "persistentjava.com";
    private int portNumber = 1433;
    private String login = "java";
    private String password = "sun";
    private String databaseName = "jdbc";
    // This is the name we will assign to our datasource. Because we are
    // using the file system provider, our name follows the file system
    // naming rules. The JNDI reserved subcontext for JDBC applications is
    // jdbc, thus our name starts appropriately.
    private String filePath = "jdbc/pjtutorial";
    public InitializeJNDI() {
        // To pass in the necessary parameters, we need to create and then
        // populate a Hashtable.
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
            "com.sun.jndi.fscontext.RefFSContextFactory");
        try {
            // Create the initial context
            Context ctx = new InitialContext(env);
            // Here we create the actual DataSource and then set the relevant
            // parameters.
            TdsDataSource ds = new TdsDataSource();
            ds.setServerName(serverName);
            ds.setPortNumber(portNumber);
            ds.setDatabaseName(databaseName);
            ds.setUser(login);
            ds.setPassword(password);
            ds.setDescription("JDBC DataSource Connection");
            // Now we bind the DataSource object to the name we selected earlier.
            ctx.bind(filePath, ds);
            ctx.close();
            // Generic Exception handler, in practice, this would be replaced by an
            // appropriate Exception handling hierarchy.
        } catch (Exception ex) {
            System.err.println("ERROR: " + ex.getMessage());
        }
    }
    public static void main(String args[]) {
        new InitializeJNDI();
    }
}




                                      Página 16 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Usar una Fuente de Datos
El ejemplo anterior establece la relación de unión entre el objeto DataSource y un nombre
particular. La mágia de JNDI realmente la realiza el proveedor de servicio apropiado. En nuestro
caso, usamos el proveedor del sistema de ficheros. Existen otras opciones, incluyendo LDAP
(Lightweight Directory Access Protocol) o incluso un DNS. Para hacer realmente una conexión,
necesitamos buscar el objeto DataSource usando el nombre al que fue unido. Observa en el
siguiente ejemplo que no hay ningún código específico de base de datos en ningún lugar:
import java.util.Hashtable ;
import javax.naming.* ;
import java.sql.* ;
import javax.sql.* ;
public class UtilizeJNDI {
    public UtilizeJNDI(){
        try {
            // We need to set up the JNDI context so that we can properly interface
            // to the correct service provider, in this case the file system.
            Hashtable env = new Hashtable() ;
            env.put(Context.INITIAL_CONTEXT_FACTORY,
            "com.sun.jndi.fscontext.RefFSContextFactory") ;
            Context ctx = new InitialContext(env) ;
            // Given the JNDI Context, we lookup the object and are returned
            // our DataSource
            DataSource ds = (DataSource)ctx.lookup("jdbc/pjtutorial") ;
            // Now we get a database connection and proceed to do our job.
            Connection con = ds.getConnection() ;
            System.out.println("Connection Established.") ;
            con.close();
            // Note that proper error handling is not included here in order to keep
            // the example short.
        }catch(Exception e ) {
            e.printStackTrace();
        }
    }
    public static void main (String args[]){
        new UtilizeJNDI() ;
    }
}




                                         Página 17 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Re-Unir una Fuente de Datos
Cuando queremos cambiar la base de datos particular o incluso el vendedor del DataSource
JDBC con el que queremos que comunique nuestro código, todo lo que necesitamos hacer es
re-unir un nuevo DataSource al nombre original. En este ejemplo, usamos el mismo driver, pero
cambiamos varios parámetros relevantes:
// We need to import the actual DataSource
import com.inet.tds.TdsDataSource;
import java.util.Hashtable;
import javax.naming.*;
import javax.naming.directory.*;
import java.sql.* ;
import javax.sql.* ;
public class InitializeJNDI {
    // First we define the relevant parameters for this datasource
    private String serverName = "persistentjava.com";
    private int portNumber = 1434; // Note the new port number
    private String login = "sun"; // New username/password combination
    private String password = "java";
    private String databaseName = "ds"; // And even a new database name.
    // We keep the same name for our datasource, just bind a new DataSource
    // to it.
    private String filePath = "jdbc/pjtutorial";
    public InitializeJNDI() {
        // Establish the proper JNDI Context
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
            "com.sun.jndi.fscontext.RefFSContextFactory");
        try {
            // Create the context
            Context ctx = new InitialContext(env);
            TdsDataSource ds = new TdsDataSource();
            ds.setServerName(serverName);
            ds.setPortNumber(portNumber);
            ds.setDatabaseName(databaseName);
            ds.setUser(login);
            ds.setPassword(password);
            ds.setDescription("JDBC DataSource Connection, take two");
            // Now we just call the rebind method with the new DataSource.
            ctx.rebind(filePath, ds);
            ctx.close();
            // Replace this with real Exception handlers in production code.
        } catch (Exception ex) {
            System.err.println("ERROR: " + ex.getMessage());
        }
    }
    public static void main(String args[]) {
        new InitializeJNDI();
    }
}




                                        Página 18 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Borrar una Fuente de Datos
Algunas veces, querremos borrar un nombre de DataSource para que no pueda volver a ser
usado:
import java.util.Hashtable ;
import javax.naming.* ;
import java.sql.* ;
import javax.sql.* ;
public class DeleteJNDI {
   public DeleteJNDI() {
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
        "com.sun.jndi.fscontext.RefFSContextFactory");
        try {
            Context ctx = new InitialContext(env);
            // unbinding the name object association effectively deletes the object.
            ctx.unbind("jdbc/pjtutorial") ;
            ctx.close() ;
        }catch (Exception ex) {
            System.err.println("ERROR: " + ex.getMessage()) ;
        }
    }
    public static void main (String args[]){
    new DeleteJNDI() ;
    }
}




                                      Página 19 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Almacenes de Conexiones

¿Por qué necesitamos Almacenes de Conexiones
Cuando usamos el DriverManager o el método DataSource para obtener conexiones a bases de
datos, cada solicitud para una nueva conexión implica una sobrecarga significante. Esto puede
impactar en el rendimiento si la obtención de nuevas conexiones ocurre con cierta frecuencia,
como podría ser el caso en un entorno de servidor Web. Para enfatizar por qué esto es cierto,
sigamos un camino potencial de una solicitud de conexión típica con una base de datos:
La aplicación Java llama a getConnection().
El código del vendedor JDBC (la implementación del driver o del DataSource) solicita una
conexión socket desde la JVM.
La JVM necesita chequear los aspectos de seguridad de la llamada potencial. Por ejemplo, los
applets sólo se pueden comunicar con el servidor del que son originarios.
Si lo aprueba, la llamada necesita pasar a través del interface de red del host hasta la LAN
corporativa.
La llamada podría necesitar pasar a través de un cortafuegos para alcanzar Internet o una
WAN.
La llamada alcanza eventualmente su subred de destino, donde podría necesitar pasar a través
de otro cortafuegos.
La llamada alcanza el host de la base de datos.
El servidor de base de datos procesa la solicitud de la nueva conexión.
Se podría necesitar requerir la licencia del servidor para determinar si hay una licencia
apropiada disponible.
La base de datos inicializa una nueva conexión cliente, incluyendo toda las sobrecargas de
memoria y sistema operativo.
La llamada de retorno es enviada de vuelta al cliente JDBC (donde tiene que pasar por todos
los cortafuegos y routers).
La JVM recibe la llamada de retorno y crea un objeto Connection apropiado.
La aplicación Java recibe el objeto Connection.
Claramente, solicitar un nuevo objeto Connection presenta una gran sobrecarga y muchos
puntos de fallo potenciales. Para minimizar esta sobrecarga, ¿por qué no reutilizar conexiones a
bases de datos en vez de borrarlas cuando hayamos terminado con ellas? Los diseñadores de
JDBC usaron este patrón de diseño popular cuando crearon el ConnectionPoolDataSource, que
nos permite crear un almacen de conexiones a bases de datos que son reutilizadas en vez de
eliminarlas cuando se cierran.

¿Qué es una PooledConnection?
Una PooledConnection es un tipo especial de conexión a base de datos que no se borra cuando
se cierra, al contrario que los objetos Connection normales (el recolector de basura puede
borrar las conexiones normales una vez que ya no son referenciadas). En en vez de esto, la
PooledConnection es almacenada para una reutilización posterior, produciendo potencialmente
una gran mejora del rendimiento. Trabajar con un almacen de conexiones a bases de datos es
casi idéntico a trabajar con objetos DataSource. Primero, en vez de crear un ejemplar de una
clase que implemente el interface DataSource, creamos un ejemplar de una clase que
implemente ConnectionPoolDataSource. Podemos usar JDNI para unir esta nueva fuente de
datos a un nombe como antes.
Para usar realmente un objeto de fuente de datos almacenado, llamamos a
getPooledConnection() sobre el ConnectionPooledDataSource, que a su vez establece
conexiones con la base de datos. Para crear un objeto Connection que será usado, llamamos a
getConnection() sobre el objeto PooledConnection en vez sobre los objetos DriverManager o
DataSource como antes. Un beneficio adicional de esta aproximación es que es mucho más fácil
manejar varios conjuntos de conexiones a bases de datos con un ConnectionPool porque él
tiene cuidado automáticamente. Esta automatización puede ser muy importante si nuestra
licencias de cliente limitan el número de clientes que pueden conectarse simultáneamente a la




                                         Página 20 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




base de datos. El proceso completo es mucho más sencillo de lo que suena, como muestran los
siguientes ejemplos.
Inicialiar un Almacen de Conexiones
En este ejemplo, usamos una base de datos mSQL y el driver JDBC de código abierto mSQL
para crear un PooledDataSource. Todo el código específico de la base de datos está contenido
en los procesos de inicialización o de unión.
// First we import the relevant package
import com.imaginary.sql.msql.* ;
import java.util.Hashtable ;
import javax.naming.* ;
public class InitializeJNDI {
    private String serverName = "localhost" ;
    private String databaseName = "jdbc" ;
    private String userName = "java" ;
    private String password = "sun" ;
    // The appropriate JNDI subcontext for PooledDataSources is jdbcpool
    private String filePath = "jdbcPool/pjtutorial" ;
    private int portNumber = 1114 ;
    private int poolSize= 10 ; // We want to create a pool with 10 connections.
    public InitializeJNDI() {
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
            "com.sun.jndi.fscontext.RefFSContextFactory");
        try {
            Context ctx = new InitialContext(env);
            // Create the PooledDataSource and set the relevant parameters.
            MsqlPooledDataSource ds = new MsqlPooledDataSource() ;
            ds.setServerName(serverName) ;
            ds.setPort(portNumber) ;
            ds.setDatabaseName(databaseName) ;
            ds.setUser(userName) ;
            ds.setPassword(password) ;
            ds.setMaxPoolSize(poolSize) ;
            // Bind the name and the DataSource object together
            ctx.bind(filePath, ds) ;
            ctx.close() ;
        } catch (Exception ex) {
            System.err.println("ERROR: " + ex.getMessage()) ;
        }
    }
    public static void main (String args[]){
        new InitializeJNDI() ;
    }
}




                                       Página 21 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Usar un Almacen de Conexiones
Una vez que hemos inicializado el PooledDataSource, ahora podemos usarlo en aplicaciones
Java para crear almacenes de conexiones a bases de datos. El siguiente ejemplo, es imaginario,
pero efectivamente demuestra los puntos importantes. Un ejemplo más realista podría ser un
servlet, que configuraría el almacen de conexiones en el método init() del servlet y
(re-)utilizaría la conexión por cada nueva solicitud del servicio:
import java.util.Hashtable ;
import javax.naming.* ;
import java.sql.* ;
import javax.sql.* ;
public class UtilizeJNDI {
    public UtilizeJNDI(){
        try {
            Hashtable env = new Hashtable() ;
            env.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.fscontext.RefFSContextFactory") ;
            Context ctx = new InitialContext(env) ;
            // Look up the DataSource given the appropriate name.
            ConnectionPoolDataSource ds
                = (ConnectionPoolDataSource)ctx.lookup("jdbcPool/pjtutorial") ;
            // A PooledConnection provides a special Connection which is not
            // destroyed when it is closed, but is instead placed back into the
            // pool of connections.
            PooledConnection pcon = ds.getPooledConnection() ;
            Connection con = pcon.getConnection() ;
            System.out.println("Connection Established") ;
            con.close();
        }
        catch(Exception e ) {
            e.printStackTrace();
        }
    }
    public static void main (String args[]){
        new UtilizeJNDI() ;
    }
}




                                        Página 22 de 23
Manejar Conexiones a Bases de Datos con JDBC 3.0




Optimizar las Comunicaciones con Bases de Datos

Métodos JDBC DataSource y Driver
Esta sección ecplia algunos de los métodos menos conocidos del API JDBC que pueden ser
utilizados para mejorar el rendimiento del sistema. Primero, todas las clases de fuentes de
datos JDBC, el Driver , el DataSource, o el ConnectionPooledDataSource, proporcionan la
habilidad de designar explícitamente un stream de salida del tipo caracter, setLogWriter(). Este
stream acepta todos los logs y mensajes de seguimiento. También hay un método disponible
para obtener el stream actual, getLogWriter(). Este puede ser extremadamente valioso cuando
intentamos diagnosticar extraños bugs o para seguir el flujo de la aplicación. Además, todas las
clases de fuentes de datos JDBc proporcionan un medio para asignar (setLoginTimeout()) u
obtener (getLoginTimeout()) la cantidad de tiempo máxima que la clase de fuente de datos
debería esperar a que se estalezca una conexión.
Una clase interesante y rara vez utilizada es la clase DriverPropertyInfo. Esta clase encapsula
toda la información de propiedades que necesita un driver para establecer una conexión a una
base de datos. DriverPropertyInfo puede usarse en una herramienta gráfica para encontrar
interactivamente los parámetros que un driver necesita y pedirle al usuario de la base de datos
los valores correctos.

Métodos JDBC Connection
Un objeto Connection o PooledConnection también tienen varios métodos que se pueden
utilizar para mejorar el rendimiento del sistema, tanto directa como indirectamente. Primero,
asumiendo que el driver JDBC y la base de datos subyacente lo soportan, un objeto connection
se puede configurar para ser de sólo lectura, setReadOnly(). Esto puede mejorar el rendimiento
del sistema para aplicaciones que no necesitan hacer cambios en la base de datos, ya que la
base de datos no necesita preocuparse de almacenar nuevas páginas, mantener entradas de
diario, o adquirir bloqueos de escritura sobre cualquiera de los datos.
Otros métodos que están relacioandos de alguna forma son setAutoCommit() y
setTransactionIsolation(). Como el descontrol de las transaciones puede causar grandes
pérdidas de rendimiento en la base de datos, estos métodos métodos y sus efecto deberían ser
claramente entenedidos y cuidadosamente aplicados.
Finalmente, un último y frecuentemente olvidado método es nativeSQL(), que taduce una
consulta SQL dada en el lenguaje de consulta nativo de la base de datos subyacente.
Examinando la versión nativa SQL de nuestra consulta, podriamos entender mejor cómo la base
de datos está intepretando nuestra consulta, y entonces hacer las modificaciones adecuadas a
nuestra aplicación para mejorar el rendimiento general.




                                         Página 23 de 23

Weitere ähnliche Inhalte

Was ist angesagt? (18)

JDBC
JDBCJDBC
JDBC
 
Java DataBase Connectivity
Java DataBase ConnectivityJava DataBase Connectivity
Java DataBase Connectivity
 
Java y Bases de Datos
Java y Bases de DatosJava y Bases de Datos
Java y Bases de Datos
 
Taller 4 - Teleinformatica
Taller 4 - TeleinformaticaTaller 4 - Teleinformatica
Taller 4 - Teleinformatica
 
JDBC
JDBCJDBC
JDBC
 
Jdbc
JdbcJdbc
Jdbc
 
Java.sql.*
Java.sql.*Java.sql.*
Java.sql.*
 
JDBC
JDBCJDBC
JDBC
 
Jdbc
JdbcJdbc
Jdbc
 
3. Curso Java JDBC (Bases de datos) - Curso 2005-2006
3. Curso Java JDBC (Bases de datos) - Curso 2005-20063. Curso Java JDBC (Bases de datos) - Curso 2005-2006
3. Curso Java JDBC (Bases de datos) - Curso 2005-2006
 
Java con base de datos
Java con base de datosJava con base de datos
Java con base de datos
 
Jdbc
JdbcJdbc
Jdbc
 
Jdbc
JdbcJdbc
Jdbc
 
J2ee jsf
J2ee jsfJ2ee jsf
J2ee jsf
 
Java con base de datos
Java con base de datosJava con base de datos
Java con base de datos
 
Introduccion Aplicaciones Web en java j2ee
Introduccion Aplicaciones Web en java j2ee Introduccion Aplicaciones Web en java j2ee
Introduccion Aplicaciones Web en java j2ee
 
POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020
POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020
POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020
 
Odbc jdbc
Odbc   jdbcOdbc   jdbc
Odbc jdbc
 

Andere mochten auch

A la unmsm memoria de aba
A la unmsm memoria de abaA la unmsm memoria de aba
A la unmsm memoria de abasanmarquino
 
Screen development applicationshome
Screen development applicationshomeScreen development applicationshome
Screen development applicationshomeLike Music
 
Pres8 medidas de_dispersion
Pres8 medidas de_dispersionPres8 medidas de_dispersion
Pres8 medidas de_dispersionLeonardo Iriarte
 
FIST for PMT352B 2010
FIST for PMT352B 2010FIST for PMT352B 2010
FIST for PMT352B 2010Dan Ward
 
(Silencio y ELE) ¡Mira quién calla! La didáctica del silencio en el aula de ELE
(Silencio y ELE) ¡Mira quién calla! La didáctica del silencio en el aula de ELE(Silencio y ELE) ¡Mira quién calla! La didáctica del silencio en el aula de ELE
(Silencio y ELE) ¡Mira quién calla! La didáctica del silencio en el aula de ELEBeatriz Méndez Guerrero
 
método de búsqueda Truncamiento
método de búsqueda Truncamientométodo de búsqueda Truncamiento
método de búsqueda TruncamientoCristopher Blum
 

Andere mochten auch (10)

A la unmsm memoria de aba
A la unmsm memoria de abaA la unmsm memoria de aba
A la unmsm memoria de aba
 
Innovación
InnovaciónInnovación
Innovación
 
Screen development applicationshome
Screen development applicationshomeScreen development applicationshome
Screen development applicationshome
 
Pres8 medidas de_dispersion
Pres8 medidas de_dispersionPres8 medidas de_dispersion
Pres8 medidas de_dispersion
 
Blah
BlahBlah
Blah
 
Fontys Project
Fontys ProjectFontys Project
Fontys Project
 
FIST for PMT352B 2010
FIST for PMT352B 2010FIST for PMT352B 2010
FIST for PMT352B 2010
 
Cadena de valor
Cadena de valorCadena de valor
Cadena de valor
 
(Silencio y ELE) ¡Mira quién calla! La didáctica del silencio en el aula de ELE
(Silencio y ELE) ¡Mira quién calla! La didáctica del silencio en el aula de ELE(Silencio y ELE) ¡Mira quién calla! La didáctica del silencio en el aula de ELE
(Silencio y ELE) ¡Mira quién calla! La didáctica del silencio en el aula de ELE
 
método de búsqueda Truncamiento
método de búsqueda Truncamientométodo de búsqueda Truncamiento
método de búsqueda Truncamiento
 

Ähnlich wie Manejo conexbd (20)

Trabajo desarrollo de soft.
Trabajo desarrollo de soft.Trabajo desarrollo de soft.
Trabajo desarrollo de soft.
 
Trabajo de jdbc
Trabajo de jdbcTrabajo de jdbc
Trabajo de jdbc
 
Trabajo de jdbc
Trabajo de jdbcTrabajo de jdbc
Trabajo de jdbc
 
JDBC
JDBCJDBC
JDBC
 
5.- PPT 2023 03 U01 T03 Lenguaje de Programación I (SP1891).pdf
5.- PPT 2023 03 U01 T03 Lenguaje de Programación I (SP1891).pdf5.- PPT 2023 03 U01 T03 Lenguaje de Programación I (SP1891).pdf
5.- PPT 2023 03 U01 T03 Lenguaje de Programación I (SP1891).pdf
 
Jdbc(desarrollo de software i yanina y yenny)
Jdbc(desarrollo de software i yanina y yenny)Jdbc(desarrollo de software i yanina y yenny)
Jdbc(desarrollo de software i yanina y yenny)
 
JCBC
JCBCJCBC
JCBC
 
Jdbc diapositivva
Jdbc diapositivvaJdbc diapositivva
Jdbc diapositivva
 
Java con Base de Datos
Java con Base de DatosJava con Base de Datos
Java con Base de Datos
 
Jdbc
JdbcJdbc
Jdbc
 
Jdbc
JdbcJdbc
Jdbc
 
POOABD (POO Aplicada a B Datos) - API JDBC - Parte 2
POOABD (POO Aplicada a B Datos) - API JDBC - Parte 2POOABD (POO Aplicada a B Datos) - API JDBC - Parte 2
POOABD (POO Aplicada a B Datos) - API JDBC - Parte 2
 
[ES] Conectividad de java a base de datos(jdbc)
[ES] Conectividad de java a base  de datos(jdbc)[ES] Conectividad de java a base  de datos(jdbc)
[ES] Conectividad de java a base de datos(jdbc)
 
Diapositivas de jdbc
Diapositivas de jdbcDiapositivas de jdbc
Diapositivas de jdbc
 
JAVA DATABASE CONNECTIVITY (JDBC)
  JAVA DATABASE CONNECTIVITY (JDBC)  JAVA DATABASE CONNECTIVITY (JDBC)
JAVA DATABASE CONNECTIVITY (JDBC)
 
Jdbc
JdbcJdbc
Jdbc
 
Jdbc
JdbcJdbc
Jdbc
 
Java con base de datos
Java con base de datosJava con base de datos
Java con base de datos
 
Acceso a datos con JDBC.pdf
Acceso a datos con JDBC.pdfAcceso a datos con JDBC.pdf
Acceso a datos con JDBC.pdf
 
Jdbc
JdbcJdbc
Jdbc
 

Mehr von Oscar Alvarez

Mehr von Oscar Alvarez (13)

Conexion dahlander
Conexion dahlanderConexion dahlander
Conexion dahlander
 
Tsx micro-pl7 v1-2
Tsx micro-pl7 v1-2Tsx micro-pl7 v1-2
Tsx micro-pl7 v1-2
 
Mq motores i
Mq motores iMq motores i
Mq motores i
 
Act p0 descripcion
Act p0 descripcionAct p0 descripcion
Act p0 descripcion
 
14 h sis.hidraulico
14 h sis.hidraulico14 h sis.hidraulico
14 h sis.hidraulico
 
Partes del bloque de cilindros
Partes del bloque de cilindrosPartes del bloque de cilindros
Partes del bloque de cilindros
 
Sellos del vastago de valvula
Sellos del vastago de valvulaSellos del vastago de valvula
Sellos del vastago de valvula
 
Historia de_los_plc_s
Historia de_los_plc_sHistoria de_los_plc_s
Historia de_los_plc_s
 
F bomba de vacio
F bomba de vacioF bomba de vacio
F bomba de vacio
 
Fuentes dvd
Fuentes dvdFuentes dvd
Fuentes dvd
 
Artrosis y homeopatía
Artrosis y homeopatíaArtrosis y homeopatía
Artrosis y homeopatía
 
Video renta
Video rentaVideo renta
Video renta
 
Ley de senos y cosenos
Ley de senos y cosenosLey de senos y cosenos
Ley de senos y cosenos
 

Manejo conexbd

  • 1. Manejar Conexiones a Bases de Datos con JDBC 3.0
  • 2. Manejar Conexiones a Bases de Datos con JDBC 3.0 Introdución al Tutorial ¿Debería leer este Tutorial? Este tutorial presenta los diferentes conceptos implicados en el establecimiento y control de una conexión con bases de datos dentro de una aplicación Java usando Java Database Connection (JDBC). Está dirigido principalmente a desarrolladores que quieren entender que "qué hay detrás de la escena" cuando usan una base de datos desde dentro de una aplicación Java Este tutorial asume que estás familiarizado con el lenguaje de programación Java. ¿Sobre qué va este Tutorial? Este tutorial demuestra cómo conectar con una base de datos usando JDBC. Aunque parece inocuo, este punto es realmente un obstáculo tanto para novatos como para veteranos en Java. Este tutorial explicará cómo una aplicación Java dentro de una JVM descubre y se comunica con una base de datos, empezando con el tradicional driver JDBC y los objetos DriverManager. Después de varios ejemplos que demuestran los cuatro tipos diferentes de drivers JDBC, el tutorial se mueve sobre una explicación de objetos DataSource que usan JNDI. También se incluye una discusión sobre JNDI, y cómo unir, usar, reunir y borrar el objeto DataSource. Finalmente, se presentan y demuestran los conceptos de almacen de conexiones, y específicamente los objetos PooledConnection. El tutorial concluye con una discusión de problemas de ajuste que normalmente se nos pasan cuando desarrollamos aplicaciones de conectividad de base de datos. Herramientas Aunque el tutorial proporciona numerosos fragmentos de código para reflejar conceptos y métodos descritos en el texto, la mayoría de la gente aprenderá mejor trabajando realmente a través de los ejemplos. Para trabajar con los ejemplos, necesitarás tener instaladas y funcionando las siguientes herramientas: Un editor de texto: los ficheros fuente Java son simplemente texto, por eso para crearlos y leerlos, necesitamos un editor de texto. Si tienen acceso a un IDE Java, puedes usarlo, pero algunas veces ocultan muchos detalles. Un entorno de desarrollo Java, como el Java2 SDK, que está disponible en http://java.sun.com/j2se/1.4/. El Java2 SDK, Standard Edition versión 1.4, incluye las extensiones estándard JDBC así como JNDI, ámbos son necesarios para algunos de los ejemplos posteriores de este tutorial Una base de datos compatible SQL: los ejemplos de este tutorial usan una amplia variedad de bases de datos para ayudarnos a demostrar cómo se puede hacer programación JDBC independiente de la base de datos. Un driver JDBC: como el API JDBC está predominantemente compuesto por interfaces, necesitamos obtener una implementación de un driver JDBC real para poder conectar realmente con una base de datos usando JDBC. Si nuestra base de datos (o nuestra maleta) no permite el uso de JDBC, siempre podemos usar el dirver puente JDBC-ODBC para conectar con cualquier base de datos (o fuente de datos) que soporta el protocolo ODBC. Página 2 de 23
  • 3. Manejar Conexiones a Bases de Datos con JDBC 3.0 Arquitectura de la Aplicación Arquitecturar Nuestro Sistema Uno de los problemas de diseño más importantes cuando desarrollamos una aplicación de bases de datos en Java es la arquitectura general del sistema; en particular, cuántos componentes diferentes deberíamos desplegar. Tradicinonalmente, esto está caracterízado por el número de capas que requiere la aplicación. Hay dos modelos arquitecturales básicos que pueden describir un sistema: el modelo de dos capas y el modelo de n-capas. Antes de entrar en los detalles del manejo de conexiones a bases de datos desde una aplicación Java, necesitamos explicar estos dos modelos. Cada modelo tiene sus propias ventajas e inconvenientes; cada uno también requiere que ciertos componentes se configuren apropiadamente, y , como resultado, cada uno funciona mejor en entornos diferentes. Las dos siguientes secciones explican en más detalle cada uno de los dos modelos arquitecturales. El Modelo de Dos Capas El modelo de dos capas es el marco de trabajo tradicional cliente-servidor; tiene una capa cliente y una capa servidor. Este modelo simple requiere que el cliente tenga cuidado específico de la base de datos. Así, por ejemplo, el cliente necesita código específico de la base de datos resultando en un acoplamiento fuerte entre las dos capas. Este acoplamiento fuerte tienes varias ventajas. Primero, puede reducir el tiempo de desarrollo debido al hecho de que todo el sistema es considerablemente más simple y más pequeño. Segundo, el acoplamiento fuerte puede mejorar potencialmente el rendimiento del sistema ya que el cliente puede fácilmente aprovecharse de las funcionalidades específicas del servidor que podrían no estar disponibles para sistemas con un acoplamiento más ligero. Por otro lado, este acoplamiento fuerte puede provocar varios problemas. El mas notable, el mantenimiento del sistema se puede volver más díficil porque los cambios en el servidor pueden romper al cliente y viceversa. Además, si la base de datos cambia, todo el código del cliente deberá ser modificado. Si el cliente está altamente distribuido, la propagación de los cambios en el sistema puede ser díficil, y en algunos escenarios imposible. Como resultado, las aplicaciones de dos capas pueden ser útiles en un entorno de LAN corporativa donde el completo control de todos los clientes se consigue, o al inicio, o en el estado prototipal de un proyecto donde diferentes opciones están siendo evaluadas. El Modelo de n-Capas El modelo de n-capas tiene una capa cliente, al menos una capa servidor, y al menos una cada intermedia. Debido a la capa extra, muchos de los problemas que afectan a los modelos de dos capas no afectarán. Por ejemplo, la capa media ahora mentiene información de la conexión a la base de datos. Esto significa que los clientes sólo tienen que conocer la capa media. Como la capa media generalmente está operando en la misma localización física que el servidor (por ejemplo, ambos componentes pueden estar detrás del mismo firewall), mantener la capa media es considerablemente más sencillo que mantener cientos de instalaciones clientes. Otra ventaja de la aproximación de n-capas es que todo el sistema se puede escalar fácilmente para manejar más usuarios.Todo lo que necesitamos hacer es añadir más capas medias o más capas servidores, dependiendo de los resultados de las operaciones de perfilado. Como las capas intermedias normalmente se implementan usado servidores Web -- usando tecnologías JavaServer Pages y Servlets -- es muy sencillo añadir balance de carga o incluso nuevos componentes hardware. Sin embargo, no todo es de color rosa, ya que la capa extra intoduce complejidad adicional en todo el sistema. Esto significa más código, más duro de probar y potencialmente más díficil de encontrar sus errores. Afortunadamente, el lenguaje Java proporciona muchos de los componentes necesarios, pre-construidos. para construir aplicaciones de n-capas viables. Además, este modelo se presta a si mismo el fácil soporte de autentificación e internacionalización, ya que la capa media controla el flujo de información y proporciona localización natural para manjear todo lo que concierne al manejo de seguridad y la localización. Página 3 de 23
  • 4. Manejar Conexiones a Bases de Datos con JDBC 3.0 Fundamentos de los Drivers JDBC Introducción a los Drivers JDBC Una inspección casual del API JDBC muestra rápidamente la dominación de los interfaces dentro del API, lo que podría llevar al usuario a preguntarse dónde se realiza el trabajo. Realmente esta es sólo una aproximación que tocan los desarrolladores JDBC porque la implementación real es la proporcionada por los vendedores de Drivers JDBC, que a su vez proporcionan las clases que implementan los interfaces necesarios. Esta aproximación presenta la competición que proporciona al consumidor más opciones, y para la mayor parte, produce mejor software. Con todos los drivers disponibles. elegir uno puede ser díficil. Aforturnadamente, Sun Microsystems mantiene una base de datos con más de 150 drivers JDBC de una amplia variedad de vendedores. Esta debería ser la primera parada después de seleccionar una base de datos. Desde una perspectiva de programación, hay dos clases principales respnsables para el establecimiento de una conexión con una base de datos. La primera clase es DriverManager, que es una de las clases que realmente proprociona el API JDBC. DriverManager es responsable de manejar un almacen de drivers registrados, esencialmente abstrayendo los detalles del uso de un driver para que el programador no tenga que tratar con ellos directamente. La segunda clase es la clase real del Driver JDBC. Estas son proporcionadas por vendedores independientes. La clase Driver JDBC es la responsable de establecer la conexión con la base de datos y de manejar todas las comunicaciones con la base de datos. Los drivers JDBC vienen en cuatro tipos diferentes Registrar un Driver JDBC El primer paso en el proceso de crear una conexión entre una aplicación Java y una base de datos es el registro de un driver JDBC con la Máquina Virtual Java (JVM) en la que se está ejecutando la aplicación Java. En el mecanimso de conexión tradicional (en oposición al mecanismo de conexión del DataSource) la conexión y todas las comunicación con la base de datos son controladas por un objeto DriverManager. Para establecer una conexión, se debe registrar un driver JDBC adecuado para la base de datos objetivo con el objeto DriverManager. La especificación JDBC, dice que se supone que los dirvers JDBC se registran automáticamente a sí mismos con el objeto DriverManager cuando se cargan en la JVM. Por ejemplo, el siguiente fragmento de código usa un inicializador estático para primero crear un ejemplar del driver JDBC persistentjava y luego resgistrarlo con el DriverManager: static { java.sql.DriverManager.registerDriver(new com.persistentjava.JdbcDriver()) ; } Registrar un driver es tan simple como cargar la clase del driver en la JVM, lo que puede hacerse de muchas maneras. Una forma es con el ClassLoader Class.forName(com.persistentjava.JdbcDriver). Otro método, que no es tan bien conocido, usa la propidad del sistema jdbc.drivers. Este método se puede usar de tres formas distintas: Desde la línea de comandos: java -Djdbc.drivers=com.persistentjava.JdbcDriver Connect Dentro de la palicación Java: System.setProperty("jdbc.drivers","com.persistentjava.JdbcDriver") ; Seleccionando la propiedad jdbc.drivers en el fichero de propiedades del sistema, que generalmente depende del sistema. Separando los drivers con una coma, se pueden registrar varios drivers usando la técnica de la propiedad del sistema mostrada arriba. Uno de los beneficios de usar la técnica de la propiedad del sistema es que se los drivers se pueden intercambiar fácilmente sin modificar ningún código (o al menos con unos mínimos cambios). Si se registran varios drivers, su orden de precedencia es: Drivers JDBC registrados por la propiedad jdbc.drivers en la inicialización de la JVM, y Drivers JDBC cargados dinámicamente. Página 4 de 23
  • 5. Manejar Conexiones a Bases de Datos con JDBC 3.0 Como la propiedad jdbc.drivers sólo se chequea una vez durante la primera invocación del método DriverManager(), es importante asegurarse de que todos los drivers están registrados correctamente antes de establecer la conexión con la base de datos. Sin embargo, no todas las JVM están creadas igual, y algunas de ellas no siguen la especificación JVM. Como resultado, los inicializadores estáticos no siempre funcionan como hemos dibujado. Esto resulta en múltiples formas de registrar un driver JDBC, incluyendo: Class.forName("com.persistentjava.JdbcDriver").newInstance(); DriverManager.registerDriver(new com.persistentjava.JdbcDriver()) ; Estas alternativas deberían funcionar bien en todas las JVMs, por eso deberíamos sentirnos agusto usándolas a lo largo del amplio conjunto de JVM disponibles. Un problema final es que Class.forname() puede lanzar una ClassNotFoundException, por eso debemos envolver el código de registro en un manejador de excepción apropiado. URLs de Drivers JDBC Una vez que un Driver JDBC se ha registrado con el DriverManager, puede usarse para establecer una conexión a una base de datos. ¿Pero cómo selecciona DriverManager el driver correcto, dado que puede haber realmente rigstrados cualquier número de drivers? (Recuerda, una sóla JVM podría soportar múltiples aplicaciones concurrentes, que podrían conectarse con diferentes bases de datos con diferentes drivers). La técnica es bastante simple: cada driver JDBC usa una URL JDBC específica (que tiene el mismo formato que una dirección Web) como un significado de auto-identificación. El formato de la URL es correcto y probablemente parece familiar: jdbc:sub-protocol:database locator. El sub-protocol es específico del driver JDBC y puede ser odbc, oracle, db2, etc., dependiendo del vendedor del driver real. El localizador de la base de datos es un indicador específico del driver para específicar de forma única la base de datos con la que una aplicación quiere interactúar. Dependiendo del tipo de driver, este localizador incluye un nombre de host, un puerto, y un nombre de sistema de base de datos. Cuando se presenta con una URL específica, el DriverManager itera sobre la colección de drivers registrados hasta que uno de ellos reconoce la URL específicada. Si no se encuentra ningún driver adecuado, se lanza una SQLException. La siguiente lista presenta varios ejemplos específicos de URLs JDBC reales: jdbc:odbc:jdbc jdbc:oracle:thin:@persistentjava.com:1521:jdbc"; jdbc:db2:jdbc Muchos drivers, incluyendo el driver puente JDBC-ODBC, acepta parámetros adicionales al final de la URL como un nombre de usuario y una password. El método para obtener una conexión a una base de datos, dando una URL JDBC específica, es llamar a getConnection() sobre el objeto DriverManager. Este método tiene varias formas: DriverManager.getConnection(url) ; DriverManager.getConnection(url, username, password) ; DriverManager.getConnection(url, dbproperties) ; Aquí url es un objeto String que es la URL JDBC, username y password son objetos String que representan el nombre de usuario y la password que la aplicación JDBC debería usar para conectar con la fuente de datos; y dbproperties es un objeto Properties de Java que encapsula todos los parámetros (posiblemente incluyendo nombre de usuario y la password) que requiere un driver JDBC para hacer una conexión con éxito. Ahora que tenemos el driver básico en la mano, podemos examinar los tipos de drivers individuales con más detalle: Página 5 de 23
  • 6. Manejar Conexiones a Bases de Datos con JDBC 3.0 Drivers del Tipo 1 Los drivers del tipo uno tienen algo en común: todos usan el puente JDBC-ODBC, que está incluido como parte estándard del JDK. Los drivers del tipo uno son diferentes al driver ODBC (Open DataBase Connectivity) adjunto al puente JDBC-ODBC. Para conectar con una fuente de datos diferente, simplemente tenemos que registrar (o unir efectivamente) una fuente de datos ODBC diferente, usando el Administrador ODBC, al nombre de la fuente de datos apropiada. Como ODBC se ha estado utilizando desde hace bastante tiempo (más que el lenguaje Java), los drivers ODBC son ubicuos. Esto hace de este tipo de drivers una buena elección para aprender cómo conectar programas Java a bases de datos. De hecho, incluso hay drivers ODBC que nos permiten asignar fuentes de datos ODBC a una aplicación Microsoft Excel o ficheros de texto plano. Sin embargo, el nivel extra de indirección, puede resultar en una pérdida de rendimiento ya que el JDBC es transferido dentro de ODBC, que luego es transferido en el protocolo específico de la base de datos. Otro problema potencial de los drivers del tipo uno es su utilización en aplicaciones distribuidas. Como el propio puente no soporta comunicación distribuida, la única forma de que los drivers del tipo uno puedan trabajar a través de la red es si el propio driver ODBC soporta interacción remota. Para drivers ODBC sencillos, esta no es una opción, y mientras que las grandes bases de datos tienen drivers ODBC que pueden trabajar de forma remota, no pueden competir con el mejor rendimiento de los drivers JDBC puro Java. Página 6 de 23
  • 7. Manejar Conexiones a Bases de Datos con JDBC 3.0 Codificación para Drivers del Tipo 1 El nombre de clase para el driver puente JDBC-ODBC es sun.jdbc.odbc.JdbcOdbcDriver y al URL JDBC toma la forma jdbc:odbc:dsn, donde dsn es el Data Source Name (nombre de la fuente de datos) usado para registrar la base de datos con el Administrador ADBC. Por ejemplo, si una base de datos se registra con una fuente de datos ODBC llamada jdbc; un nombre de usuario de java y una password de sun, se puede usar el siguiente fragmento de código para establecer una conexión. Nota: En interés de la claridad y la brevedad, se ha eliminado del listado el chequeo y manejo de errores. Posteriores ejemplos, demostrarán la importancia de estos mecanismos (específicamente, la captura de errores encadenando sentencias SQLException). String url = "jdbc:odbc:jdbc" ; Connection con ; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ; } catch(java.lang.ClassNotFoundException e) { System.err.print("ClassNotFoundException: ") ; System.err.println(e.getMessage()) ; return ; } try { con = DriverManager.getConnection(url, "java", "sun"); } catch(SQLException ex) { System.err.println("SQLException: " + ex.getMessage()); } finally { try{ con.close ; } catch(SQLException ex) { System.err.println(SQLException: " + ex.getMessage()) ; } } Página 7 de 23
  • 8. Manejar Conexiones a Bases de Datos con JDBC 3.0 Drivers del Tipo 2 Los drivers del tipo dos también son conocidos como drivers Java parciales, porque traducen directamente el API JDBC en un API específico de la base de datos. La aplicación cliente de base de datos (para el propóstio de este tutorial, el host que está ejecutando la JVM) debe tener las librerías cliente apropiadas para la base de datos, que podrían incluir código binario instalado y posiblemente ejecutándose. Para una aplicación distribuida, este requerimietno puede introducir problemas extra con las licencias, así como posibles pesadillas con los problemas de distribución de código. Por ejemplo, usar un modelo del tipo dos restringe a los desarrolladores a utilizar plataformas y sistemas operativos soportados por la librería cliente de la base de datos. Sin embargo, este modelo puede funcionar eficientemente, cuando la base cliente está fuertemente controlada.. Esto ocurre típicamente en LANs corporativas. Un ejemplo de driver del tipo dos es el driver de aplicación JDBC para DB2. El siguiente ejemplo demuestra cómo establecer una conexión usando un driver DB2: String url = "jdbc:db2:jdbc" ; try { Class.forName("COM.ibm.db2.jdbc.app.DB2Driver") ; } catch(java.lang.ClassNotFoundException e) { System.err.print("ClassNotFoundException: ") ; System.err.println(e.getMessage()) ; return ; } ... Observa la similitud que tiene este fragmento de código con el del ejemplo 1. Esta es la principal característica del modelo del tipo 2: la curva de aprendizaje para un programador que se mueve de un modelo a otro es prácticamente inexistente. Los dos últimos tipos de drivers son drivers puro Java. El beneficio de los drivers puro Java es su fácil despliegue en entonos altamente distribuidos. Página 8 de 23
  • 9. Manejar Conexiones a Bases de Datos con JDBC 3.0 Drivers del Tipo 3 Los drivers del tipo tres son drivers puro Java que transforman el API JDBC en un protocolo independiente de la base de datos. El driver JDBC no comunica directamente con la base de datos; comunica con un servidor de capa media, que a su vez comunica con la base de datos. Este nivel extra de indirección proporciona flexibilidad en que se puede acceder a diferentes bases de datos desde el mismo código porque el servidor de la capa media oculta las especificidades a la aplicación Java. Para cambiar a una base de datos diferente, sólo necesitamos cambiar los parámetros en el servidor de la capa media. (Un punto a observar: el formato de la base de datos a la que estamos accediendo debe ser soportado por el servidor de la capa media). El lado negativo de los drivers del tipo tres es que el nivel extra de indirección puede perjudicar el rendimiento general del sistema. Por otro lado, si una aplicación necesita interactúar con una variedad de formatos de bases de datos, un driver del tipo tres en una aproximación adecuada debido al hecho de que se usa el mismo driver JDBC sin importar la base de datos subyacente. Además, como el servidor de la capa media se puede instalar sobre una plataforma hardware específica, se pueden realizar ciertas optimizaciones para capitalizar los resultados perfilados. Página 9 de 23
  • 10. Manejar Conexiones a Bases de Datos con JDBC 3.0 Drivers del Tipo 4 Los drivers del tipo cuatro son drivers puro Java que se comunican directamente con la base de datos. Muchos programadores consideran éste el mejor tipo de driver, ya que normalmente proporciona un rendimiento óptimo y permite al desarrollador utilizar las funcionalidades específicas de la base de datos. Por supuesto este acoplamiento puede reducir la flexibilidad, especialmente si necesitamos cambiar la base de datos subyacente en una aplicación. Este tipo de driver se usa frecuentemente en applets y otras aplicaciones altamente distribuidas. El siguiente fragmento de código muestra cómo usar un driver DB2 del tipo cuatro: String url = "jdbc:db2://persistentjava.com:50000/jdbc" ; try { Class.forName("COM.ibm.db2.jdbc.net.DB2Driver") ; } catch(java.lang.ClassNotFoundException e) { System.err.print("ClassNotFoundException: ") ; System.err.println(e.getMessage()) ; return ; } ... Página 10 de 23
  • 11. Manejar Conexiones a Bases de Datos con JDBC 3.0 Un Ejemplo Completo de Driver del Tipo 4 El siguiente ejemplo muestra cómo usar un driver JDBC de un vendedor de terceras partes, en este caso Merant, para conectar con una base de datos DB2. DB2 UDB requiere información adicional, no estándard para establecer la conexión a la base de datos, que en este ejemplo están añadidos a la URL JDBC como parámetros opcionales. package com.persistentjava; import java.sql.*; public class ConnectMerantDB2 { static { try { Class.forName("com.merant.datadirect.jdbc.db2.DB2Driver").newInsta nce(); } catch (Exception e) { System.out.println(e); } } public static void main(String args[]) { String url = "jdbc:merant:db2://persistentjava.com:50000;" ; url += "DatabaseName=jdbc;CollectionId=DEFAULT;" ; url += "PackageName=JDBCPKG;CreateDefaultPackage=TRUE"; Connection con; System.out.println("Connecting"); try { con = DriverManager.getConnection(url, "java", "sun"); System.out.println("Connection Established"); con.close(); // In this example, the proper handling of SQLExceptions is // demonstrated as they can be potentially chained. } catch (SQLException e) { System.out.println("nERROR:----- SQLException -----n"); while (e != null) { System.out.println("Message: " + e.getMessage()); System.out.println("SQLState: " + e.getSQLState()); System.out.println("ErrorCode: " + e.getErrorCode()); e.printStackTrace(); e = e.getNextException(); } } } } Página 11 de 23
  • 12. Manejar Conexiones a Bases de Datos con JDBC 3.0 Transaciones con Bases de Datos Transaciones Básicas Uno concepto que causa problemas a los principiantes en el mundo del desarrollo de aplicaciones de base de datos es la idea de transaciones. Fundamentalmente, una transación representa una unidad de trabajo lógica. Como la principal responsabilidad de una base de datos es preservar la información, necesita tener algo que le indique a un usuario que se debe salvar el estado actual del programa. De igual forma, cuando las cosas han ido mal, necesita una forma para indicar que una base de datos deberia ignorar el estado actual y volver a atrás, al estado del programa salvado anteriormente. En el idioma de las bases de datos, estas funciones se llaman entregar una transación y deshacer una transación, respectivamente. Para realizar estas tareas, el API JDBC incluye dos métodos como parte del interface Connection. Dando un objeto Connection llamado con, el estado del programa se graba llamando a con.commit(), para volver al estado salvado anteriormente, con.rollback(). Estos dos métodos pueden lanzar SQLExceptions si algo va mal cuando la base de datos realice realmente la operación, por eso necesitamos envolverlos en bloques try ... catch. Más sobre Transaciones En un entorno mono-usuairo, las transaciones son bastantes sencillas de entender -- simplemente implican salvar o deshacer el estado de una aplicación. Sin embargo, en modo multi-usuario, las transaciones son más complejas. La demostración clásica de una transación multi-usuario es una cuenta bancaria donde una aplicación está intentando hacer un cargo mientras otra aplicación está intentando hacer un depósito en la misma cuenta. Si estas familiarizado con la programación concurrente (también conocida como programación multi- thread), probablemente hayas visto este problema antes. El problema fundamental es que a menos que las dos transaciones estén aisladas la una de la otra, una aplicación podría interrumpir a la otra resultando en un estado del programa incorrecto. En nuestra sencilla demostración, esto podría significar una cuenta con un saldo erróneo, algo que no es precisamente bueno para retener clientes. Pueden aparecer tres problemas comunes cuando tratamos con varios usuarios que acceden a los mismos datos: Lecturas sucias. Un lectura sucia ocurre cuando una aplicación usa datos que han sido modificados por otra aplicación, y esos datos están en un estado sin entregar. La segunda aplicación entonces solicita que los datos que fueron modificados sean desechos. Entonces los datos de la primera transación están corruptos o "sucios". Lecturas no-repetibles. Una lectura no-repetible ocurre cuando una transación obtiene datos, que posteriormente son alterados por una transación separada, y la primera transación re-lee los datos ahora alterados. Así, la primera transación hizo una lectura no-repetible. Lecturas fantasmas. Una lectura fantasma ocurre cuando una transación adquiere datos mediante alguna consulta, otra transación modifica algunos de los datos, y la transación original recupera los datos una segunda vez. La primera transación ahora tendrá un conjunto de resultados diferentes, que podrían contener datos fantasmas. Niveles de Transación Para resolver los problemas asociados a múltiples threads solicitando los mismos datos, las transaciones están aisladas unas de otras por bloqueos. La mayoría de las bases de datos soportan diferentes tipos de bloqueo; por lo tanto, el API JDBC soporta diferentes tipos de transaciones, que son asignadas o determinadas por el objeto Connection. En el API JDBC tiene disponibles los siguientes niveles de transaciones: TRANSACTION_NONE indica que las transaciones no están soportadas. TRANSACTION_READ_UNCOMMITTED indica que una transación puede ver los cambios de otra transación antes de ser entregada. Así están permitidas las lecturas sucias, las lecturas no- repetibles, y las lecturas fantasmas. Página 12 de 23
  • 13. Manejar Conexiones a Bases de Datos con JDBC 3.0 TRANSACTION_READ_COMMITTED indica que la lectura de datos no entregados, no está permitida. Este nivel todavía permite que ocurran las lecturas no-repetibles y las lecturas fantasmas. TRANSACTION_REPEATABLE_READ indica que una transación está garantizada que pueda re- leer el mismo dato sin fallar, pero las lecturas fantasmas todavía pueden ocurrir. TRANSACTION_SERIALIZABLE es la transación de más alto nivel y evita que ocurran las lecturas sucias, las lecturas no-repetibles y las lecturas fantasmas. Podríamos preguntarnos porqué todas las transaciones no operan en modo TRANSACTION_SERIALIZABLE para garantizar el grado más alto de integridad de datos. El problema es, de forma similar a los problemas implicados con el manejo de la programación de múltiples threads, que cuanto más sea el nivel de protección de transación, más alta será la pérdida de rendimiento. Dando un objeto Connection podemos seleccionar explícitamente el nivel de transación, asumiendo que nuestra base de datos y nuestro driver JDBC soporten esta característica: con.setTransactionLevel(TRANSACTION_SERIALIZABLE) ; También podemos determinar el nivel de transación actual: if(con.getTransactionLevel() == TRANSACTION_SERIALIZABLE) System.out.println("Highest Transaction Level in operation.") ; Lotes y Transaciones Por defecto, los drivers JDBC operan en lo que se llama modo autoentrega. En este modo, todos los comandos enviados a la base de datos operan en su propia transación. Aunque esto puede ser útil para los principiantes, implica una pérdida de rendimiento porque las transaciones requieren una cierta cantidad de sobrecarga para configurar todo apropiadamente. Si queremos poder controlar explícitamente las entregas y los retrocesos (deshacer la transación), necesitamos desactivar el modo autocommit: con.setAutoCommit(false) ; También podemos determinar rápidamente el modo autocommit de un objeto Connection dado: if(con.getAutoCommit() == true) System.out.println("Auto Commit mode"); Muchas bases de datos soportan lotes, en los que se minimiza la sobrecarga de transaciones realizando múltiples operaciones update de la base de datos en una sóla operación, o lote. Las operaciones por lotes fueron introducidas en JDBC 2.0 y requieren que una transación no esté en modo autocommit. En el siguiente ejemplo tenemos una operación por lotes, que asume que existe una Connection a una base de datos que tiene una sola tabla: con.setAutoCommit(false) ; Statement stmt = connection.createStatement() ; stmt.addBatch("INSERT INTO people VALUES('Joe Jackson', 0.325, 25, 105) ; stmt.addBatch("INSERT INTO people VALUES('Jim Jackson', 0.349, 18, 99) ; stmt.addBatch("INSERT INTO people VALUES('Jack Jackson', 0.295, 15, 84) ; int[] updateCounts = stmt.executeBatch() ; con.commit() ; Observa que el método executeBatch() devuelve un array de cuentas actualizadas, una por cada operación del lote. Un último problema con las operaciones por lotes es que pueden lanzar una nueva excepción del tipo BatchUpdateException, lo que indica que falló al menos uno de los comandos del lote. Por eso, necesitamos añadir un manejador de excepciones correspondiente a nuestras operaciones por lotes. Control Fino de las Transaciones Empezando con el API JDBC 3.0, se añadió un nuevo elemento interface relacionado con las transaciones. Este interface presenta el concepto de savepoints. Los Savepoints proporcionan un marca dentro de una aplicación de base de datos que puede usarse como un argumento cuando se llama al método rollback. Como resultado, usando el API JDBC 3.0, ahora es posible seleccionar un savepoint antes de empezar una interacción complicada con la base de datos y, dependiendo del resultado, entregar la transación completa o deshacer hasta el savepoint y devolver la aplicación a un punto conocido. Página 13 de 23
  • 14. Manejar Conexiones a Bases de Datos con JDBC 3.0 Para seleccionar un punto de salvado, creamos un objeto Savepoint desde el objeto Connection, como se ve aquí: Savepoint svpt = con.setSavepoint("Savepoint") ; Para deshacer hasta un Savepoint dado, simplemente le pasamos el objeto Savepoint deseado al método rollback: con.rollback(svpt) ; Cuando no se necesitan más, liberamos todos los objetos Savepoint para liberar los caros recursos de la base de datos para otros usuarios: con.releaseSavepoint(svpt) ; Observa que cuando entregamos o deshacemos una transación, cualquier Savepoints creado podría convertirse en inválido dependiendo del orden exacto y del tipo de operación. Puedes ver la especificación del API JDBC 3.0 o el manual de tu driver para más información. Página 14 de 23
  • 15. Manejar Conexiones a Bases de Datos con JDBC 3.0 Fuentes de Datos Fuentes de Datos Básicas Uno de los principales benficios de usar el API JDBC es facilitar una programación independiente de la base de datos, así la mayoría de las aplicaciones JDBC pueden transferirse fácilmente a otra base de datos diferente. Sin embargo, todavía hay dos ítems que permacenen unidos a una base de datos particular, la clase JDBC Driver y la URL JDBC. Con la introdución de las fuentes de datos en el API JDBC 2.0, se eliminaron incluso estas dependencias. Esencialmente un objeto DataSource representa una fuente de datos particular en una aplicación Java. Además de encapsular la información específica de la base de datos y del driver JDBC en un sólo objeto estándarizado, las fuentes de datos pueden actuar como una factoría de Connection y proporcionar métodos para seleccionar y obtener propiedades particulares que requiere el objeto DataSource para una operación satisfactoria. Algunas propiedades estándar que podría requerir un objeto DataSource incluyen: ·databaseName ·serverName ·portNumber ·userName ·password Un beneficio adicional de usar una DataSource, que podrías haber adivinado de la lista anterior, es que la información sensible relacionada con la seguridad como el nombre de usuario, la password, e incluso el servidor de la base de datos están códificados sólo en un lugar, lo que puede hacer un administrador de sistemas. Mientras que la interacción con un objeto DataSource se puede hacer con una aplicación gráfica, es instructivo ver como trabajan realmente los ejemplos. Aunque los conceptos de un objeto DataSource son bastantes simples, para usarlo dentro de una aplicación Java, un objeto DataSource es referenciado usando Java Naming and Directory Interface, o JNDI. Antes de saltar dentro del código de ejemplo de DataSource, el siguiente punto presenta conceptos relevantes de JNDI que son necesarios para usar apropiadamente un objeto DataSource. Repaso Rápido de JNDI JNDI es un API Java que encapsula el concepto de servidores de nombres y directorios de la misma forma que JDBC encapsula los conceptos que hay detrás de la comunicación con una base de datos. Aunque podría parecer confuso, es bastante sencillo -- todos lo usuarios de ordenadores usan servicios de nombres y directorios todos los días. Por ejempo, los discos duros trabajan con pistas y sectores, aunque un usuario sólo se preocupa de nombres de ficheros y directorios. El sistema de ficheros maneja el servicio de nombrado que asocia un nombre de fichero dado con una localización específica en el disco duro. Otro ejemplo es la Web, donde la mayoría de los usuarios sólo se preocupan del nombre de la Web site, como www.persistentjava.com, y no de la dirección IP subyacente. Sin embargo, la comunicación TCP/IP se hace usando la dirección IP y no usando el nombre que leemos los humanos. La transformación entre las dos representaciones la realiza el DNS, o Domain Name System. Aunque JDNI proporciona un API ámplio y útil por sí mismo, nuestras necesidades son considerablemente simples. En breve, necesitamos conocer como hacer cuatro cosas: ·Crear un nombre y unirlo a un objeto Java. ·Buscar un nombre para recuperar un objeto Java. ·Borrar un nombre. ·Re-unir un nombre a nuevo objeto Java. En vez de proporcionar ejemplos JNDI imaginarios para las tareas anteriores, las siguientes secciones muestran ejemplos de estas tareas usando fuentes de datos JDBC. Todos estos ejemplos usan el proveedor de sistema de ficheros, que es una descarga separada. Página 15 de 23
  • 16. Manejar Conexiones a Bases de Datos con JDBC 3.0 Registrar una Fuente de Datos Este ejemplo es una implementación de un DataSource de tereceras partes de i-net software para conectar con una base de datos MS SQL Server. Los comentarios en el código marcan los puntos importantes de registro (o inicialziación) de una fuente de datos JDBC: // We need to import the actual DataSource implementation import com.inet.tds.TdsDataSource; import java.util.Hashtable; import javax.naming.*; import javax.naming.directory.*; import java.sql.* ; import javax.sql.* ; public class InitializeJNDI { // First we define the relevant parameters for this datasource private String serverName = "persistentjava.com"; private int portNumber = 1433; private String login = "java"; private String password = "sun"; private String databaseName = "jdbc"; // This is the name we will assign to our datasource. Because we are // using the file system provider, our name follows the file system // naming rules. The JNDI reserved subcontext for JDBC applications is // jdbc, thus our name starts appropriately. private String filePath = "jdbc/pjtutorial"; public InitializeJNDI() { // To pass in the necessary parameters, we need to create and then // populate a Hashtable. Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); try { // Create the initial context Context ctx = new InitialContext(env); // Here we create the actual DataSource and then set the relevant // parameters. TdsDataSource ds = new TdsDataSource(); ds.setServerName(serverName); ds.setPortNumber(portNumber); ds.setDatabaseName(databaseName); ds.setUser(login); ds.setPassword(password); ds.setDescription("JDBC DataSource Connection"); // Now we bind the DataSource object to the name we selected earlier. ctx.bind(filePath, ds); ctx.close(); // Generic Exception handler, in practice, this would be replaced by an // appropriate Exception handling hierarchy. } catch (Exception ex) { System.err.println("ERROR: " + ex.getMessage()); } } public static void main(String args[]) { new InitializeJNDI(); } } Página 16 de 23
  • 17. Manejar Conexiones a Bases de Datos con JDBC 3.0 Usar una Fuente de Datos El ejemplo anterior establece la relación de unión entre el objeto DataSource y un nombre particular. La mágia de JNDI realmente la realiza el proveedor de servicio apropiado. En nuestro caso, usamos el proveedor del sistema de ficheros. Existen otras opciones, incluyendo LDAP (Lightweight Directory Access Protocol) o incluso un DNS. Para hacer realmente una conexión, necesitamos buscar el objeto DataSource usando el nombre al que fue unido. Observa en el siguiente ejemplo que no hay ningún código específico de base de datos en ningún lugar: import java.util.Hashtable ; import javax.naming.* ; import java.sql.* ; import javax.sql.* ; public class UtilizeJNDI { public UtilizeJNDI(){ try { // We need to set up the JNDI context so that we can properly interface // to the correct service provider, in this case the file system. Hashtable env = new Hashtable() ; env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory") ; Context ctx = new InitialContext(env) ; // Given the JNDI Context, we lookup the object and are returned // our DataSource DataSource ds = (DataSource)ctx.lookup("jdbc/pjtutorial") ; // Now we get a database connection and proceed to do our job. Connection con = ds.getConnection() ; System.out.println("Connection Established.") ; con.close(); // Note that proper error handling is not included here in order to keep // the example short. }catch(Exception e ) { e.printStackTrace(); } } public static void main (String args[]){ new UtilizeJNDI() ; } } Página 17 de 23
  • 18. Manejar Conexiones a Bases de Datos con JDBC 3.0 Re-Unir una Fuente de Datos Cuando queremos cambiar la base de datos particular o incluso el vendedor del DataSource JDBC con el que queremos que comunique nuestro código, todo lo que necesitamos hacer es re-unir un nuevo DataSource al nombre original. En este ejemplo, usamos el mismo driver, pero cambiamos varios parámetros relevantes: // We need to import the actual DataSource import com.inet.tds.TdsDataSource; import java.util.Hashtable; import javax.naming.*; import javax.naming.directory.*; import java.sql.* ; import javax.sql.* ; public class InitializeJNDI { // First we define the relevant parameters for this datasource private String serverName = "persistentjava.com"; private int portNumber = 1434; // Note the new port number private String login = "sun"; // New username/password combination private String password = "java"; private String databaseName = "ds"; // And even a new database name. // We keep the same name for our datasource, just bind a new DataSource // to it. private String filePath = "jdbc/pjtutorial"; public InitializeJNDI() { // Establish the proper JNDI Context Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); try { // Create the context Context ctx = new InitialContext(env); TdsDataSource ds = new TdsDataSource(); ds.setServerName(serverName); ds.setPortNumber(portNumber); ds.setDatabaseName(databaseName); ds.setUser(login); ds.setPassword(password); ds.setDescription("JDBC DataSource Connection, take two"); // Now we just call the rebind method with the new DataSource. ctx.rebind(filePath, ds); ctx.close(); // Replace this with real Exception handlers in production code. } catch (Exception ex) { System.err.println("ERROR: " + ex.getMessage()); } } public static void main(String args[]) { new InitializeJNDI(); } } Página 18 de 23
  • 19. Manejar Conexiones a Bases de Datos con JDBC 3.0 Borrar una Fuente de Datos Algunas veces, querremos borrar un nombre de DataSource para que no pueda volver a ser usado: import java.util.Hashtable ; import javax.naming.* ; import java.sql.* ; import javax.sql.* ; public class DeleteJNDI { public DeleteJNDI() { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); try { Context ctx = new InitialContext(env); // unbinding the name object association effectively deletes the object. ctx.unbind("jdbc/pjtutorial") ; ctx.close() ; }catch (Exception ex) { System.err.println("ERROR: " + ex.getMessage()) ; } } public static void main (String args[]){ new DeleteJNDI() ; } } Página 19 de 23
  • 20. Manejar Conexiones a Bases de Datos con JDBC 3.0 Almacenes de Conexiones ¿Por qué necesitamos Almacenes de Conexiones Cuando usamos el DriverManager o el método DataSource para obtener conexiones a bases de datos, cada solicitud para una nueva conexión implica una sobrecarga significante. Esto puede impactar en el rendimiento si la obtención de nuevas conexiones ocurre con cierta frecuencia, como podría ser el caso en un entorno de servidor Web. Para enfatizar por qué esto es cierto, sigamos un camino potencial de una solicitud de conexión típica con una base de datos: La aplicación Java llama a getConnection(). El código del vendedor JDBC (la implementación del driver o del DataSource) solicita una conexión socket desde la JVM. La JVM necesita chequear los aspectos de seguridad de la llamada potencial. Por ejemplo, los applets sólo se pueden comunicar con el servidor del que son originarios. Si lo aprueba, la llamada necesita pasar a través del interface de red del host hasta la LAN corporativa. La llamada podría necesitar pasar a través de un cortafuegos para alcanzar Internet o una WAN. La llamada alcanza eventualmente su subred de destino, donde podría necesitar pasar a través de otro cortafuegos. La llamada alcanza el host de la base de datos. El servidor de base de datos procesa la solicitud de la nueva conexión. Se podría necesitar requerir la licencia del servidor para determinar si hay una licencia apropiada disponible. La base de datos inicializa una nueva conexión cliente, incluyendo toda las sobrecargas de memoria y sistema operativo. La llamada de retorno es enviada de vuelta al cliente JDBC (donde tiene que pasar por todos los cortafuegos y routers). La JVM recibe la llamada de retorno y crea un objeto Connection apropiado. La aplicación Java recibe el objeto Connection. Claramente, solicitar un nuevo objeto Connection presenta una gran sobrecarga y muchos puntos de fallo potenciales. Para minimizar esta sobrecarga, ¿por qué no reutilizar conexiones a bases de datos en vez de borrarlas cuando hayamos terminado con ellas? Los diseñadores de JDBC usaron este patrón de diseño popular cuando crearon el ConnectionPoolDataSource, que nos permite crear un almacen de conexiones a bases de datos que son reutilizadas en vez de eliminarlas cuando se cierran. ¿Qué es una PooledConnection? Una PooledConnection es un tipo especial de conexión a base de datos que no se borra cuando se cierra, al contrario que los objetos Connection normales (el recolector de basura puede borrar las conexiones normales una vez que ya no son referenciadas). En en vez de esto, la PooledConnection es almacenada para una reutilización posterior, produciendo potencialmente una gran mejora del rendimiento. Trabajar con un almacen de conexiones a bases de datos es casi idéntico a trabajar con objetos DataSource. Primero, en vez de crear un ejemplar de una clase que implemente el interface DataSource, creamos un ejemplar de una clase que implemente ConnectionPoolDataSource. Podemos usar JDNI para unir esta nueva fuente de datos a un nombe como antes. Para usar realmente un objeto de fuente de datos almacenado, llamamos a getPooledConnection() sobre el ConnectionPooledDataSource, que a su vez establece conexiones con la base de datos. Para crear un objeto Connection que será usado, llamamos a getConnection() sobre el objeto PooledConnection en vez sobre los objetos DriverManager o DataSource como antes. Un beneficio adicional de esta aproximación es que es mucho más fácil manejar varios conjuntos de conexiones a bases de datos con un ConnectionPool porque él tiene cuidado automáticamente. Esta automatización puede ser muy importante si nuestra licencias de cliente limitan el número de clientes que pueden conectarse simultáneamente a la Página 20 de 23
  • 21. Manejar Conexiones a Bases de Datos con JDBC 3.0 base de datos. El proceso completo es mucho más sencillo de lo que suena, como muestran los siguientes ejemplos. Inicialiar un Almacen de Conexiones En este ejemplo, usamos una base de datos mSQL y el driver JDBC de código abierto mSQL para crear un PooledDataSource. Todo el código específico de la base de datos está contenido en los procesos de inicialización o de unión. // First we import the relevant package import com.imaginary.sql.msql.* ; import java.util.Hashtable ; import javax.naming.* ; public class InitializeJNDI { private String serverName = "localhost" ; private String databaseName = "jdbc" ; private String userName = "java" ; private String password = "sun" ; // The appropriate JNDI subcontext for PooledDataSources is jdbcpool private String filePath = "jdbcPool/pjtutorial" ; private int portNumber = 1114 ; private int poolSize= 10 ; // We want to create a pool with 10 connections. public InitializeJNDI() { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); try { Context ctx = new InitialContext(env); // Create the PooledDataSource and set the relevant parameters. MsqlPooledDataSource ds = new MsqlPooledDataSource() ; ds.setServerName(serverName) ; ds.setPort(portNumber) ; ds.setDatabaseName(databaseName) ; ds.setUser(userName) ; ds.setPassword(password) ; ds.setMaxPoolSize(poolSize) ; // Bind the name and the DataSource object together ctx.bind(filePath, ds) ; ctx.close() ; } catch (Exception ex) { System.err.println("ERROR: " + ex.getMessage()) ; } } public static void main (String args[]){ new InitializeJNDI() ; } } Página 21 de 23
  • 22. Manejar Conexiones a Bases de Datos con JDBC 3.0 Usar un Almacen de Conexiones Una vez que hemos inicializado el PooledDataSource, ahora podemos usarlo en aplicaciones Java para crear almacenes de conexiones a bases de datos. El siguiente ejemplo, es imaginario, pero efectivamente demuestra los puntos importantes. Un ejemplo más realista podría ser un servlet, que configuraría el almacen de conexiones en el método init() del servlet y (re-)utilizaría la conexión por cada nueva solicitud del servicio: import java.util.Hashtable ; import javax.naming.* ; import java.sql.* ; import javax.sql.* ; public class UtilizeJNDI { public UtilizeJNDI(){ try { Hashtable env = new Hashtable() ; env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory") ; Context ctx = new InitialContext(env) ; // Look up the DataSource given the appropriate name. ConnectionPoolDataSource ds = (ConnectionPoolDataSource)ctx.lookup("jdbcPool/pjtutorial") ; // A PooledConnection provides a special Connection which is not // destroyed when it is closed, but is instead placed back into the // pool of connections. PooledConnection pcon = ds.getPooledConnection() ; Connection con = pcon.getConnection() ; System.out.println("Connection Established") ; con.close(); } catch(Exception e ) { e.printStackTrace(); } } public static void main (String args[]){ new UtilizeJNDI() ; } } Página 22 de 23
  • 23. Manejar Conexiones a Bases de Datos con JDBC 3.0 Optimizar las Comunicaciones con Bases de Datos Métodos JDBC DataSource y Driver Esta sección ecplia algunos de los métodos menos conocidos del API JDBC que pueden ser utilizados para mejorar el rendimiento del sistema. Primero, todas las clases de fuentes de datos JDBC, el Driver , el DataSource, o el ConnectionPooledDataSource, proporcionan la habilidad de designar explícitamente un stream de salida del tipo caracter, setLogWriter(). Este stream acepta todos los logs y mensajes de seguimiento. También hay un método disponible para obtener el stream actual, getLogWriter(). Este puede ser extremadamente valioso cuando intentamos diagnosticar extraños bugs o para seguir el flujo de la aplicación. Además, todas las clases de fuentes de datos JDBc proporcionan un medio para asignar (setLoginTimeout()) u obtener (getLoginTimeout()) la cantidad de tiempo máxima que la clase de fuente de datos debería esperar a que se estalezca una conexión. Una clase interesante y rara vez utilizada es la clase DriverPropertyInfo. Esta clase encapsula toda la información de propiedades que necesita un driver para establecer una conexión a una base de datos. DriverPropertyInfo puede usarse en una herramienta gráfica para encontrar interactivamente los parámetros que un driver necesita y pedirle al usuario de la base de datos los valores correctos. Métodos JDBC Connection Un objeto Connection o PooledConnection también tienen varios métodos que se pueden utilizar para mejorar el rendimiento del sistema, tanto directa como indirectamente. Primero, asumiendo que el driver JDBC y la base de datos subyacente lo soportan, un objeto connection se puede configurar para ser de sólo lectura, setReadOnly(). Esto puede mejorar el rendimiento del sistema para aplicaciones que no necesitan hacer cambios en la base de datos, ya que la base de datos no necesita preocuparse de almacenar nuevas páginas, mantener entradas de diario, o adquirir bloqueos de escritura sobre cualquiera de los datos. Otros métodos que están relacioandos de alguna forma son setAutoCommit() y setTransactionIsolation(). Como el descontrol de las transaciones puede causar grandes pérdidas de rendimiento en la base de datos, estos métodos métodos y sus efecto deberían ser claramente entenedidos y cuidadosamente aplicados. Finalmente, un último y frecuentemente olvidado método es nativeSQL(), que taduce una consulta SQL dada en el lenguaje de consulta nativo de la base de datos subyacente. Examinando la versión nativa SQL de nuestra consulta, podriamos entender mejor cómo la base de datos está intepretando nuestra consulta, y entonces hacer las modificaciones adecuadas a nuestra aplicación para mejorar el rendimiento general. Página 23 de 23