Almacen de Conexiones

Si hemos usado SQL u otra herramienta similar para conectarnos con una base de datos y actúar sobre los datos, probablemente habremos notado que la obteneción de la conexión y el login es la parte que tarda más tiempo. Una aplicación puede fácilmente tardar varios segundos cada vez que necesita establecer una conexión.

El varsiones anteriores a JDBCTM 2.0 cada sesión de base de datos requería una nueva conexión y un login incluso si la conexión anterior usaba la misma tabla y cuenta de usuario. Si estámos usando versioens anteriores al JDBC 2.0 y queremos mejorar el rendimiento, podemos cachear las conexiones JDBC.

Las conexiones cacheadas se mantienen un objeto pool en tiempo de ejecución y pueden ser utilizadas y reutilizadas cuando las necesite la aplicación. Una forma de implementar un objeto pool es hacer una una simple hashtable de objetos conection. Sin embargo, una forma más sencilla de hacerlo es escribir un driver JDBC envuelto que es un intermediario entre la aplicación y la base de datos.

La envoltura trabaja particulamente en los Beans de Enterprise que san persistencia manejada por el Bean por dos razones: 1) Sólo se carga una clase Driver por cada Bean, y 2) los detalles específicos de la conexión se manejan fuera del Bea.

Esta sección explica cómo escribir una clase Driver JDBC envuelta


Clases Wrapper

El Driver JDBC envuelto creado para estos ejemplos consta de las siguientes clases:

Driver de Conexión

La clase JDCConnectionDriver.java implementa el interface java.sql.Driver, que proporciona método para cargar drivers y crear nuevas conexiones a bases de datos.

Un objeto JDCConnectionManager es creado por una aplicación que pretende una conexión con una base de datos. La aplicación proprociona el ULR para la base de datos, el ID del usuario y la password.

El constructor JDCConnectionManager hace esto:

public JDCConnectionDriver(String driver, 
                String url, 
                String user, 
                String password) 
        throws  ClassNotFoundException,
                InstantiationException, 
                IllegalAccessException, 
                SQLException {

  DriverManager.registerDriver(this);
  Class.forName(driver).newInstance();
  pool = new JDCConnectionPool(url, user, password);
}
Cuando el programa llamante necesita una conexión con la base de datos, llama al método JDCConnectionDriver.connect, que a su vez, llama al método JDCConnectionPool.getConnection.

Almacen de Conexiones

La clase JDCConnectionPool.java tiene conexiones disponibles para el programa llamando en su método getConnection. Este método busca una conexión disponible en el almacen de conexiones. Si no hay ninguna disponible, crea una nueva conexión. Si hay una conexión disponible en el almacen, el método getConnection alquila la conexión y la devuelve al programa llamante.
public synchronized Connection getConnection() 
	throws SQLException {

  JDCConnection c;
  for(int i = 0; i < connections.size(); i++) {
     c = (JDCConnection)connections.elementAt(i);
     if (c.lease()) {
        return c;
     }
  }

  Connection conn = DriverManager.getConnection(
			url, user, password);
  c = new JDCConnection(conn, this);
  c.lease();
  connections.addElement(c);
  return c;
}
La clase JDCConnection.java representa una conexión JDBC en el almacen de conexiones, y esencialmente es una envoltura alrededor de un conexión real JDBC. El objeto JDCConnection mantiene una bandera de estado para indicar si la conexión está en uso y el momento en que la conexión se sacó del almacen. Este tiempo es usado por la clase ConnectionReaper.java para identificar las conexiones colgadas.

Bloqueos y Cuelgues

Mientras que muchos clientes y servidores de bases de datos tiene formas de manejar los bloqueos y los cuelgues y no tenemos que preocuparnos de escribir código para manejar estas situaciones, muchos de los nuevos modelos de base de datos ligeros distribuidos no están tan bien equipados. La clase conection pool proporciona una cosechador de conexiones muerta para manejar dichas situacciones.

La clase ConnectionReaper decide que una clase está muerta cuando se cumplen las siguientes condiciones:

El chequeo de validación ejecuta una simple consulta SQL sobre la conexión para ver si lanza una excepción. En este ejemplo, el método de validación solicita una descripción de alto nivel de las tablas de la base de datos. Si una conexión falla el test de validación, se cierra, se inicia una nueva conexión con la base de datos y se añade al almacen de conexiones.
public boolean validate() {
  try {
     conn.getMetaData();
  }catch (Exception e) {
     return false;
  }
  return true;
}

Cerrar Conexiones

La conexiónes devuelta al almacen de conexiones cuando el programa llamante llama al método JDCConnection.close en su claúsulafinally.
public void close() throws SQLException {
  pool.returnConnection(this);
}

Aplicación de Ejemplo

Usamos un almacen de conexiones en una aplicación de forma similar a como usaríamos cualquiere otro driver JDBC. Aquí está el código de un RegistrationBean controlado por el Bean. Este RegistrationBean se ha adaptado desde la casa de subastas de JavaBeans enterprise descrito en los coaítulo 1 -3.

Cuando se crea el primer objeto RegistrationBean, crea un ejemplar estático de la clase JDCConnectionDriver. Este objeto driver estático se registra a sí mismo con el DriverManager en el constructor JDCConnectionDriver poniendo disponibles la solicitudes de conexiones para todos los objetos RegistrationBean creados por la aplicación cliente.

Pasar la URL como jdbc:jdc:jdcpool en el método getConnection permite que el DriverManager corresponda la getConnection solicitada al driver registrado. El DriverManager usa un sencillo String para encontrar un driver disponible que pueda manejar URLs en ese formato.

public class RegistrationBean implements EntityBean{

  private transient EntityContext ctx;
  public String theuser, password; 
  public String	creditcard, emailaddress;
  public double balance;

//Static class instantiation
  static {
        try{
        new pool.JDCConnectionDriver(
		"COM.cloudscape.core.JDBCDriver", 
		"jdbc:cloudscape:ejbdemo",
		"none", "none");
        }catch(Exception e){}
  }

  public Connection getConnection() 
                      throws SQLException{
        return DriverManager.getConnection(
				"jdbc:jdc:jdcpool");
  }
}

Ozito