Newsgroup: it.comp.java
Titolo: Tomcat e pool di connessioni: come si implementa?

Ciao,
ho provato a configurare il pool di connessioni di Tomcat 4.1.18, seguendo
le istruzioni
riportate nella documentazione: JNDI Datasource HOW-TO. Il problema che
riscontro
è che le connessioni vengono allocate continuamente e mai riutilizzate.
Basta fare il refresh di una pagina jsp per allocare ogni volta una nuova
connessione. Allego il blocco di configurazione della mia applicazione e la
classe
TestDb che implementa un semplice accesso al database. Non riesco a capire
se è un problema di configurazione oppure se sbaglio a scrivere il codice.
entrambe le cose le ho quasi integralmente copiate dalla documentazione.
Saluti a tutti i lettori del newgroup.
Vincenzo.
************** SERVER.XML *************
....
        <Context path="/testpool" docBase="c:\testpool" debug="1"
reloadable="true" crossContext="true">
    <Logger className="org.apache.catalina.logger.FileLogger"
prefix="localhost_testpool_log." suffix=".txt"
               timestamp="true"/>
    <Resource name="jdbc/TestPool" auth="Container"
type="javax.sql.DataSource"/>
    <ResourceParams name="jdbc/TestPool">
      <parameter>
        <name>factory</name>
        <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
      </parameter>
       <parameter>
           <name>maxActive</name>
           <value>20</value>
        </parameter>
        <parameter>
           <name>maxIdle</name>
           <value>10</value>
        </parameter>
        <parameter>
           <name>maxWait</name>
           <value>-1</value>
        </parameter>
      <!-- Firebird dB username and password for dB connections  -->
      <parameter>
          <name>username</name>
          <value>TESTUSER</value>
      </parameter>
      <parameter>
          <name>password</name>
          <value>testpwd</value>
      </parameter>
      <!-- Class name for Firebird JDBC driver -->
      <parameter>
         <name>driverClassName</name>
         <value>org.firebirdsql.jdbc.FBDriver</value>
      </parameter>
      <!-- Firebird DB Url -->
      <parameter>
        <name>url</name>
<value>jdbc:firebirdsql:
127.0.0.1/3050:C:/programmi/interbase/data/TESTDB.GD
B</value>
      </parameter>
    </ResourceParams>
  </Context>
....
****************************************
****************  DbTest.java *************
package foo;
import javax.naming.*;
import javax.sql.*;
import java.sql.*;
public class DbTest {
  String foo = "Not Connected";
  int bar = -1;
  public void init() {
    Connection conn = null;
    Statement stmt = null;  // Or PreparedStatement if needed
    ResultSet rst = null;
    try{
      Context ctx = new InitialContext();
      if(ctx == null ) throw new Exception("Boom - No Context");
      DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/TestPool");
      if (ds != null) {
        conn = ds.getConnection();
        if(conn != null)  {
            foo = "Got Connection "+conn.toString();
            stmt = conn.createStatement();
            rst = stmt.executeQuery("select * from nomi");
            if(rst.next()) {
               foo=rst.getString(2);
               bar=rst.getInt(3);
            }
            conn.close();
        }
      }
    } catch (Exception e) {
         e.printStackTrace();
    } finally {
        if (rst != null) {
           try { rst.close(); } catch (SQLException e) { ; }
           rst = null;
        }
        if (stmt != null) {
           try { stmt.close(); } catch (SQLException e) { ; }
           stmt = null;
        }
        if (conn != null) {
           try { conn.close(); } catch (SQLException e) { ; }
           conn = null;
        }
    }
 }
 public String getFoo() { return foo; }
 public int getBar() { return bar;}
}
****************************************
***************** test.jsp *****************
<html>
  <head>
    <title>Db Test</title>
  </head>
  <body>
  <%
    foo.DbTest tst = new foo.DbTest();
    tst.init();
  %>
  <h2>Results</h2>
    Foo <%= tst.getFoo() %><br/>
    Bar <%= tst.getBar() %>
  </body>
</html>
***************************************

 riutilizzate. 
Devi mantenere l'istanza del DataSource in vita. Se ogni volta ricrei un 
DataSource nuovo, ogni volta viene creato un nuovo pool.
In genere io lo gestisco nel context (come proprietà) e lo creo tramite un 
contextListener nell'evento di creazione.

 DataSource nuovo, ogni volta viene creato un nuovo pool.
Mi spiace contraddirti ma è Tomcat che si preoccupa di tenere in vita il 
DataSource, lui ne ottieni soltanto un riferimento via JNDI. Le risorse 
gestite dal container servono proprio a questo scopo.
Vincenzo: ho dato un'occhiata al codice ma sinceramente non mi pare di 
vedere nulla di sbagliato. Io proverei a testarlo con un altro db 
(mysql, hsqldb) per accertarmi che non sia un problema di compatibilità 
tra firebird e jakarta dbcp.
Ciao.
\mirko

 tra firebird e jakarta dbcp.
Ciao Mirko,
dopo avere debuggato una ad una le righe del codice, ho verificato
che il comando "rs.GetInt(1)" mi restituiva una eccezione. Correggendo
il comando SQL le connessioni vengono riutilizzate. Ma restano
comunque altri dubbi:
1) nel codice che ho postato mi assicuro di rilasciare la connessione
    anche dopo una eccezione, ma ciò comunque non basta per permettere
    il riutilizzo della stessa;
2) dopo avere eseguito il refresh della pagina per un numero di volte uguale
    al parametro "maxIdle" non riesco ad avere una connessione funzionante,
    ottengo un "null"; inoltre rilevo che le connessioni aperte verso il DB
sono
    tre o quattro, mentre il parametro "maxActive" è impostato a 20 e quindi
    se Tomcat non riesce ad avere una connessione disponibile tra quelle già
    aperte dovrebbe comunque crearne una nuova, almeno fino 20.
Forse intendo male il concetto di Pool di connessioni, oppure non comprendo
bene il significato dei parametri di configurazione.
Aiutatemi a  capire.
Grazie Vincenzo.

 ha
scritto:
[CUT]
Prova a dare un'occhiata alla voce _Common Problems_ dalla zezione
_JNDI Datasource HOW-TO_ da cui hai estratto l'esempio.


Se ti capita durante la chiusura dei vari ammenicoli un'eccezione non SQL la connessione
non la chiudi, il costrutto try/finally va usato in modo diverso. Un esempio di uso
corretto e' il seguente:
    Connection conn = ...
    try
    {
        ....
        PreparedStatement pstm = conn.prepareStatement(...);
        try
        {
            ResultSet rslt = pstm.executeQuery();
            try
            {
                ....
            }
            finally
            {
                rslt.close();
            }
        }
        finally
        {
            pstm.close();
        }
    }
    finally
    {
        conn.close();
    }
Quello che apri, chiudi. Prova a rimettere in questo modo il tuo codice e verifica che le
connessioni a fronte di un errore (puoi generarlo intenzionalmente te) vengano sempre
chiuse: almeno un dubbio su tre te lo togli :-)
Ciao,
    Bruno.
-- 
| Bruno Bossola 
| A Java Software Engineer :-)
| 
http://digilander.iol.it/bbossola
|
| Membro del JUG Torino - 
http://www.jugtorino.it
| 

     }
Ciao Bruno,
ho sostituito il codice che avevo scritto con quello che hai proposto.
In effetti l'errore che rilevavo in precedenza non era un errore SQL
ma un errore di conversione.
Ho provato a lanciare delle eccezioni all'interno di ogni blocco e
finalmente
la "risorsa" connessione viene liberata correttamente.
Grazie per l'aiuto.
Ora sto cercando di capire il significato degli altri parametri di
configurazione
del pool, ma anche la documentazione delle Api non č granchč.
Ho scoperto perň che nel log di Tomcat, ogni volta che ricevo una
connessione
"null" compare un messaggio del tipo:
           "DBCP borrowObject failed: null"
ma non sono riuscito a trovare la documentazione in merito.
Grazie ancora Vincenzo.