Pool Conexiones DBCP

Buenas,
Soy nueva en el foro, pero les pido que me ayuden!!, Hace unos añitos ya, realice una aplicación pero resulta que comenzó a fallar por el número de conexiones, así que decidí usar el pool de conexiones dbcp, la clase compila bien pero al momento de correr mi programa en el tomcat 6, estoy programando en jsp,no me genera error pero no me muestra la consulta, yo tenía una clase de conexión anterior que no usaba pool pero me funcionaba y consultaba correctamente, no se que este haciendo mal, esta es la clase:

package prueba;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import javax.naming.InitialContext;
/**
* Ejemplo simple de uso de BasicDataSource.
*
* @author Chuidiang
*/

public class BaseDatos{
/**
* @param args
*/

protected ResultSet rs;
/** Pool de conexiones */
private DataSource dataSource;
/**
* Inicializa el pool de conexiones BasicDataSource y realiza una insercion
* y una consulta
*/

public BaseDatos() {
inicializaDataSource();
}
/**
* Inicializacion de BasicDataSource
*/

private void inicializaDataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName("org.postgresql.Driver");
basicDataSource.setUsername("postgres");
basicDataSource.setPassword("54");
basicDataSource.setUrl("jdbc:postgresql://localhost:5432/prueba");
// Opcional. Sentencia SQL que le puede servir a BasicDataSource
// para comprobar que la conexion es correcta.
System.out.println("Validar conexion");
basicDataSource.setValidationQuery("select 1");
dataSource = basicDataSource;
}
/**
* Realiza una insercion, pidiendo una conexion al dataSource y cerrandola
* inmediatamente despues, para liberarla.
*/

public boolean insertar(String inser) throws Exception {
System.out.println("Sentencia que llega Insertar: "+inser);
Connection conexion = null;
boolean s=false;
try {
// BasicDataSource nos reserva una conexion y nos la devuelve.
System.out.println("Entro a insertar, antes del getConnection");
conexion = dataSource.getConnection();
System.out.println("Conexión del Método Insertar"+conexion);
if(conexion!=null){
// La insercion.
Statement ps = conexion.createStatement();
ps.executeUpdate(inser);
s=true;
}
else{
s=false;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
liberaConexion(conexion);
}
return s;
}
/**
* Cierra la conexion. Al provenir de BasicDataSource, en realidad no se
* esta cerrando. La llamada a close() le indica al BasicDataSource que
* hemos terminado con dicha conexion y que puede asignarsela a otro que la
* pida.
*
* @param conexion
*/

private void liberaConexion(Connection conexion) {
try {
if (null != conexion) {
// En realidad no cierra, solo libera la conexion.
conexion.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* Realiza una consulta a la base de datos y muestra los resultados en
* pantalla.
*/

public ResultSet consultar(String consu)throws Exception{
System.out.println("Sentencia que llega Consultar: "+consu);
Connection conexion = null;
try {
System.out.println("Entro a consultar, antes del getConnection");
conexion = dataSource.getConnection();
System.out.println("Conexión del Método Consultar"+conexion);
Statement sentencia = conexion.createStatement();
rs= sentencia.executeQuery(consu);
} catch (SQLException e) {
e.printStackTrace();
} finally {
// En el finally, para asegurar que se ejecuta, se cierra la
// conexion.
liberaConexion(conexion);
}
System.out.println("ResultSet"+rs);
return rs;
}
public boolean validar(String consul)throws Exception{
boolean sesion=false;
Connection conexion = null;
try {
System.out.println("Entro a validar, antes del getConnection");
conexion = dataSource.getConnection();
System.out.println("Conexión del Método Validar"+conexion);
Statement sentencia = conexion.createStatement();
rs= sentencia.executeQuery(consul);
if(rs.next())sesion=true;
} catch (SQLException e) {
e.printStackTrace();
} finally {
// En el finally, para asegurar que se ejecuta, se cierra la
// conexion.
liberaConexion(conexion);
}
return sesion;
}
}

Gracias!

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de DianitaYPP

Solucioné una parte

De nuevo yo, hice una modificación al código, y en la parte donde mando a imprimir el resultset me muestra los datos de la consulta, es decir, que si se llena y si se conecta a la base de datos, pero, en el index1.jsp no se muestra nada, es decir, desde la aplicación si envía el select que necesitó, en la clase si se llena el rs, pero debería mostrar en el y no muestra nada, que podrá ser???
---------------------------------------------------------------------------------
Lo que adicione al código:

 private DataSource getJdbcMiData() throws Exception{
        Context c=new InitialContext();
        return (DataSource)c.lookup("java:comp/env/jdbc/postgres");
    }
    /**
     * Realiza una consulta a la base de datos y muestra los resultados en
     * pantalla.
     */

   public ResultSet consultar(String consu)throws Exception{
        System.out.println("Sentencia que llega Consultar: "+consu);
       
        try {
                //System.out.println("Entro a consultar, antes del getConnection");
                //conexion=this.dbc();segundo
            //conexion = dataSource.getConnection();primero
           conexion=this.getJdbcMiData().getConnection();
            System.out.println("Conexión del Método Consultar"+conexion);
            Statement sentencia = conexion.createStatement();
            rs= sentencia.executeQuery(consu);
           
            if(rs.next()){System.out.println("El resulset esta lleno");}
            System.out.println("ResultSet"+rs.next());
       
         
        } catch (SQLException e) {
            e.printStackTrace();
        }
         System.out.println("Salio del try catch");
         while(rs.next()){
         System.out.println(rs.getString("client"));
         }
         liberaConexion(conexion);
         return rs;
    }
------------------------------------------------
index1.jsp

<select name="client"  id="client">
  <%
      try{
        ResultSet r = paciente.consultarUsuariosTodo();
        while(r.next()){%>
  <option value="<%=r.getString("client")%>"> <%=r.getString("client")%></option>
  <%}
      }
      catch(SQLException e){
      e.getMessage();
      }
     %>
</select>

--------------------------------------
Clase Paciente-Método consultarUsuariosTodo()

public ResultSet consultarUsuariosTodo()throws Exception{
        BaseDatos bd=new BaseDatos();
        String sql=new String("SELECT client,login,type FROM usuario WHERE activacion=true");
        return bd.consultar(sql);
     }

----------------------------------
Alguna idea de que podrá hacer??? Porfaaa ayudaaa!!!!!!

Imagen de luxspes

Haz oido de las etiquetas

Haz oido de las etiquetas code? Si las usas sera mas facil que la gente entienda tu pregunta y te pueda ayudar...

Imagen de DianitaYPP

Gracias

Lo siento, gracias, ya lo edite :)

Imagen de ezamudio

consulta

El ResultSet que devuelves ya no sirve para nada, porque ya cerraste la conexión de donde viene.

Pero... como es un pool, la conexión realmente no se cierra, sino que regresa al pool, pero no sé si haya alguna advertencia en el log de que estás dejando cosas abiertas (en este caso, el ResultSet y el Statement).

En general está mal tu patrón de uso del ResultSet; no deberías estar devolviendo ResultSets así. Los ResultSets necesitan que la conexión de donde vienen esté abierta para poder usarlos, y al final hay que cerrar el ResultSet, el Statement que lo creó y finalmente la conexión. Tu método de liberar conexión está mal porque solamente cierra la conexión, pero el método de insertar por ejemplo tampoco cierra el statement.

Imagen de DianitaYPP

This ResultSet is closed.

Hola! Gracias por responder, efectivamente estaba leyendo el log del tomcat y sale el mensaje sobre el ResultSet, te comentó, es que el método consultar debe retornar el ResultSet, pero no sé como aparte de retornarlo, liberar la conexión, me podrías explicar? :( es la primera vez que uso dbcp...intente incluso, utilizar un set y un get para llenar una copia del ResultSet cuando se llena, y poderlo recuperar, pero tampoco funciona :(

org.postgresql.util.PSQLException: This ResultSet is closed.
        at org.postgresql.jdbc2.AbstractJdbc2ResultSet.checkClosed(AbstractJdbc2ResultSet.java:2839)
        at org.postgresql.jdbc2.AbstractJdbc2ResultSet.next(AbstractJdbc2ResultSet.java:1889)
        at org.apache.tomcat.dbcp.dbcp.DelegatingResultSet.next(DelegatingResultSet.java:168)
        at clinica.BaseDatos.getLista(BaseDatos.java:183)
        at clinica.Paciente2.consultarUsuariosTodo(Paciente2.java:128)
        at org.apache.jsp.index1_jsp._jspService(index1_jsp.java:157)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:388)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
        at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:879)
        at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:600)
        at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1703)
        at java.lang.Thread.run(Unknown Source)
Imagen de ezamudio

no se puede

La respuesta corta: no se puede. Si devuelves un ResultSet, es porque dejas la conexión abierta. Pero tienes que tener mucho cuidado con el manejo de los recursos en ese caso. Quien haya obtenido el ResultSet debe cerrar la conexión y cualquier otro recurso abierto al final. La definición de "al final" es lo crucial aquí.

Si es una app web, una opción es implementar el patrón open session in view, o bien NO devolver un ResultSet sino los resultados que contiene, en forma de una lista de mapas o de objetos de alguna clase (pero eso ya se acerca peligrosamente a hacer tu propio ORM). Para ambas opciones existen bibliotecas y/o frameworks que ya implementan eso para que no lo tengas que hacer a patín, por ejemplo el JdbcTemplate de Spring.

Imagen de DianitaYPP

:(

Estaba pensando en guardar los datos del ResultSet en una lista y retornar la lista... y así poder cerrar la conexion, el statement y el resultset...voy a leer sobre JdbcTemplate, gracias por responder!

Imagen de apolonioluis

yo uso yank jdbc es muy

yo uso yank jdbc es muy ligero y facil de usar, es una alternativa ligth a hibernate.

Imagen de Gallosuarez

Por si aún te sirve ...

DianitaYPP:

Ignoro si ya pudiste solucionar tu problema, sin embargo, te dejo una liga donde puedes revisar algunos ejemplos en el uso correcto de commons-dbcp.

http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/doc/

Saludos,
Gerardo Suárez Trejo

Imagen de DianitaYPP

Si Gracias, los había tomado

Si Gracias, los había tomado de ejemplos..pero no me sirve porque no me permite retornar el resultset.

Imagen de DianitaYPP

Hola, disculpa, he estado

He estado leyendo acerca de JdbcTemplate, sea la solución que escoja igual debo modificar mis jsp´s pues solo puedo lograr que retorne un list y no un resultset, así que modifico mi pregunta: cuál es la manera más eficiente de manejar mis conexiones pool? usando JdbcTemplate o el Dbcp, es decir, si tuvieran las dos opciones, cuál escogerían? Ya que el cambio se me volvió engorroso, quiero estar segura de escoger la mejor opción, :( consejos?....y de antemano, gracias a todos por sus respuestas!!!

Imagen de neko069

Correcciones mencionadas

Pues lo del ResultSet como te dicen que lo uses, es llenar una lista de objetos (tienes/puedes crear uno) algo así se me ocurre:

//este seria el pojo, y con objetos de este tipo construyes tu lista
public class Usuario implements Serializable{
    private String client;
    private String login;
    private String type;
//suponiendo que todos son Strings, le agregas los getters y setters
}

Luego, la forma en cómo ciclas el ResultSet sería más o menos así (tomando tu método original):

   //cambiamos el tipo de objeto de retorno
   public List<Usuario>consultar(String consu)throws Exception{
        System.out.println("Sentencia que llega Consultar: "+consu);
       
        try {
           List<Usuario> usuarios = new ArrayList<Usuarios>();
           conexion=this.getJdbcMiData().getConnection();
            Statement sentencia = conexion.createStatement();
            rs= sentencia.executeQuery(consu);
            while(rs.next()){
                 //creamos un objeto Usuario por cada registro en tu result set
                 Usuario u = new Usuario();
                 u.setClient(rs.getString("CLIENT"));  //lo llenamos con datos
                 u.setLogin(rs.getString("LOGIN"));
                 u.setType(rs.getString("TYPE"));
                 usuarios.add(u);  //se agrega a la lista
             }
             liberaConexion(conexion); /*aqui liberas la conexion, no vi la implementacion, asi que no tengo opinion aca              aunque tambien podrias meter este metodo en un bloque finally
*/

             return usuarios;

        } catch (SQLException e) {
            e.printStackTrace();
        }
         return null;
    }

En tu otra clase (Paciente) y en tu jsp (index1.jsp) Ya tendrías que modificar acorde. El código es puramente de muestra y me lo hice al vuelo, así que puede tener fallas, checa qué te sirve, y ya que funcione como quiere, postea tú código para la posteridad del foro ;-)

Imagen de DianitaYPP

Gracias neko069, que tonta no

Gracias neko069, que tonta no había pensado en eso, que me aconsejas tú?, seguir usando dbcp o implementar JdbcTemplate? En cuanto a rendimiento y demás características, cuál es mejor?

Imagen de ezamudio

nada que ver

Dbcp y JdbcTemplate son dos cosas completamente separadas, no tienen nada que ver una con la otra, hacen cosas distintas y usar una no implica que no uses la otra. Dbcp es un pool de conexiones a base de datos implementado como un DataSource. JdbcTemplate es un componente que usa un DataSource para interactuar con una base de datos sin tener que estar peleándose con conexiones; sus métodos obtienen una conexión y siempre la cierran al final y si ocurre una excepción la traducen a tiempo de ejecución.

Imagen de DianitaYPP

Me queda claro :) Mil gracias

Me queda claro :) Mil gracias

Imagen de DianitaYPP

Solucionado

Clase Base Datos

package prueba;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingException;
import java.util.List;
import java.util.ArrayList;

/**
 * Ejemplo simple de uso de BasicDataSource.
 *
 * @author Chuidiang
 */

public class BaseDatos{

    /**
     * @param args
     */

     protected ResultSet rs;
     public String[] r= null;
 
    /** Pool de conexiones */
    private DataSource dataSource;

   public Connection conexion = null;
   
    public BaseDatos() {
       
           
        inicializaDataSource();
       
    }

   
    private void inicializaDataSource() {
           
        BasicDataSource basicDataSource = new BasicDataSource();
        basicDataSource.setDriverClassName("org.postgresql.Driver");
        basicDataSource.setUsername("postgres");
        basicDataSource.setPassword("54");
        basicDataSource.setUrl("jdbc:postgresql://localhost:5432/prueba");

        // Opcional. Sentencia SQL que le puede servir a BasicDataSource
        // para comprobar que la conexion es correcta.
        //System.out.println("Validar conexion");
        //basicDataSource.setValidationQuery("select 1");

        dataSource = basicDataSource;
    }

 private DataSource getJdbcMiData() throws Exception{
        Context c=new InitialContext();
        return (DataSource)c.lookup("java:comp/env/jdbc/postgres");
    }
   
  /**
     * Cierra la conexion. Al provenir de BasicDataSource, en realidad no se
     * esta cerrando. La llamada a close() le indica al BasicDataSource que
     * hemos terminado con dicha conexion y que puede asignarsela a otro que la
     * pida.
     *
     * @param conexion
     */

    private void liberaConexion(Connection conexion,Statement sentencia,ResultSet rs) {
        try {
            if (null != conexion) {
                // En realidad no cierra, solo libera la conexion.
                conexion.close();
                rs.close();
                sentencia.close();
           
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
   
     private void liberaConexion(Connection conexion,Statement sentencia) {
        try {
            if (null != conexion) {
                // En realidad no cierra, solo libera la conexion.
                conexion.close();
                sentencia.close();
           
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
       
    public void insertar(String inser) throws Exception {
         
        Connection conexion = null;
       
        Statement ps=null;
        try {
             conexion=this.getJdbcMiData().getConnection();          
           
            if(conexion!=null){
             // La insercion.
            ps = conexion.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
            ps.executeUpdate(inser);
           
            }  

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
           liberaConexion(conexion,ps);
           
        }
       
            }

     
 public List<Usuario> consultarUsuariosTodo(String consu)throws Exception{
    //    System.out.println("Sentencia que llega Consultar: "+consu);
       ResultSet c=null;
       Statement sentencia=null;
       List<Usuario> usuarios = new ArrayList<Usuario>();
                        try {
                                 
               
            conexion=this.getJdbcMiData().getConnection();
            //System.out.println("Conexión del Método Consultar"+conexion);
            sentencia = conexion.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
            rs= sentencia.executeQuery(consu);
           
            while(rs.next()){
               
                 Usuario u = new Usuario();
                 u.setCliente(rs.getString("client"));  
                 u.setLogin(rs.getString("login"));
                 u.setType(rs.getString("type"));
                 usuarios.add(u);  
                 
            }
           
            this.liberaConexion(conexion,sentencia,rs);
            return usuarios;
           
        } catch (SQLException e) {
            e.printStackTrace();
        }
         
        return null;               
           
               
    }
           
   
}

----Clase Usuario--------

package prueba;

import java.io.Serializable;

public class Usuario implements Serializable{
    private String client;
    private String login;
    private String type;
   

Usuario (){
}
//Métodos Set
public void setCliente(String cliente){
        this.client=cliente;
}

public void setLogin(String log){
        this.login=log;
}

public void setType(String tipo){
        this.type=tipo;
}

//Metodos get

public String getCliente(){
        return this.client;
}

public String getLogin(){
        return this.login;
}

public String getType(){
        return this.type;
}

}

------Paciente.java-----

public List<Usuario> consultarUsuariosTodo()throws Exception{
        BaseDatos bd=new BaseDatos();
        String sql=new String("SELECT client,login,type FROM usuario WHERE activacion=true");
        return bd.consultarUsuariosTodo(sql);
     }

----index1.jsp------

<select name="client"  id="client">
  <%
      try{
        List<Usuario> r = paciente.consultarUsuariosTodo();
       
        Iterator iter = r.iterator();
while (iter.hasNext()){
  String client=((Usuario)iter.next()).getCliente();

                  %>
  <option value="<%=client%>"> <%=client%></option>
  <%}
      }
      catch(SQLException e){
      e.getMessage();
      }
     %>
</select>
                         

La solución sugerida por Neko069 funcionando :) Gracias!!

Imagen de DianitaYPP

JdbcTemplate

En esta página explican con un ejemplo el JdbcTemplate, estaré probando de esta otra manera:

Ejemplo

Imagen de ezamudio

BaseDatos

Tu clase BaseDatos sigue estando mal, sólo cierras la conexión (y el statement y demás) si todo sale bien; si se arroja una excepción no haces nada (sólo la imprimes, pero se queda abierta la conexión). El método liberaConexion lo debes invocar en el finally, no al final del try.

Imagen de neko069

Ejem...

Gracias por publicar tu respuesta, algunos detalles:
- Abres conexión (Connection), sentencia (Statement) y resultados(ResultSet) y los cierras en el mismo orden ... NO; para cerrar el orden es ResultSet, Statement y Connection.
-Para crear tu connection pool, yo encontré otros ejemplos que son de las docs de commons dbcp, acá, acá y acá, son alternativas a tu configuración, igual puedes checar los ejemplos, y a tu criterio (y tiempo) ver si hay alguna ventaja en hacerlo como se ilustra.

Para lo de Spring, antes de que eches mano de cualquier tutorial en blogs, mejor busca en la documentación, por decir algo, en las docs de la versión 3.2échale una leída al apartado de... bueno, lee todo (si no conoces Spring, comienza desde el apartado III Core Technologies y luego te regresas a leer lo primero), pero en la Parte 4, apartado 14 (parece código penal) está lo referente a jdbcTemplate, aunque te repito, todo es importante, y para un ejemplo completo, bájate el Pet clinic y juega con el código.

Edito: Haz caso a las sugerencias de Enrique, él sabe de lo que habla.

Imagen de DianitaYPP

Gracias por corregir, sería

Gracias por corregir, sería así?

public List<Usuario> consultarUsuariosTodo(String consu)throws Exception{
   
       ResultSet c=null;
       Statement sentencia=null;
       List<Usuario> usuarios = new ArrayList<Usuario>();
                        try {
                                 
               
            conexion=this.getJdbcMiData().getConnection();
       
            sentencia = conexion.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
            rs= sentencia.executeQuery(consu);
           
            while(rs.next()){
               
                 Usuario u = new Usuario();
                 u.setCliente(rs.getString("client"));  
                 u.setLogin(rs.getString("login"));
                 u.setType(rs.getString("type"));
                 usuarios.add(u);  
                 
            }
           
                        return usuarios;
           
        } catch (SQLException e) {
            e.printStackTrace();
        } finally{
               
           try { if (rs != null) rs.close(); } catch(Exception e) { }
            try { if (sentencia != null) sentencia.close(); } catch(Exception e) { }
            try { if (conexion != null) conexion.close(); } catch(Exception e) { }
        }
         
        return null;               
           
               
    }
 
Imagen de ezamudio

Se ve bien, eso debería cerrar la conexión incluso si hay problemas. Aunque no entiendo por qué conexion no es una variable local; no debe ser un campo porque entonces vas a tener muchos problemas cuando varios hilos usen el mismo objeto.

Si estás en Java 7, tal vez puedes usar el try-with-resources. Ejemplos aquí.

try (Connection conexion = getJdbcMiData().getConnection();
     Statement sentencia = conexion.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
     ResultSet rs = sentencia.executeQuery(consu)) {
  while (rs.next()) {
    //blabla
  }
  return usuarios;
} catch (SQLException ex) {
  //hacer algo con la excepción, no nada más "tragársela"
}
return null;
Imagen de DianitaYPP

Gracias Ezamudio!!! Me haz

Gracias Ezamudio!!! Me haz ayudado muchisimo!!!! cambiaré conexión a variable a local...