Newsgroup: it.comp.java
Titolo: [LUNGO]Websphere 5 e RolledbackException

Salve ragazzi,
ho scritto un'applicazione con struts, tomcat, JSTL 1.1 ed Oracle 9i.
Finche' il tutto gira sotto Tomcat, non ci sono problemi, non appena
pero' faccio il deploy su websphere ho la seguente eccezione, ogni
volta che eseguo una query.
[Errore servlet]-[init]: Impossibile caricare il servlet:
com.ibm.ws.LocalTransaction.RolledbackException	at
com.ibm.ws.LocalTransaction.LocalTranCoordImpl.cleanup(LocalTranCoordImpl.java:1073)
Ho letto in questo ng, su un post precedente, che questo avviene ogni
volta che non chiudo la connessione nel medesimo metodo in cui la apro
e che provoca una rollback sul database.
Da parte mia e' voluto il fatto di aprire una connessione e di
chiuderla altrove, perche' ad esempio ho necessita' di effettuare piu'
query e committare o rollbackare solo alla fine.
Inoltre ho verificato in query di insert, che il tutto viene
correttamente inserito nel db.
Insomma, mi devo preoccupare???
Saluti,
Davide Gurgone.

 query e committare o rollbackare solo alla fine.
La specifica J2EE prevede che tutte le connessioni debbano essere chiuse nel 
metodo che le ha aperte. In caso contrario, č il container a chiuderle 
eseguendo un'azionde di default che č una rollback (anche se was consente di 
impostare come defaultaction una commit, cosa che ti sconsiglio caldamente).
Per risolvere il tuo problema (piů accessi a db e commit finale)  devi 
utilizzare le transazioni. Cosě apri (e chiudi!) tutte le connessioni che 
vuoi e poi decidi se eseguire il commit o la rollback.
Scorpio. 

Uso gia' le transazioni ed e' proprio questo il motivo per cui non
posso chiudere la connessione prima di aver terminato le operazioni di
insert/update.
Infatti le transazioni sono a livello di connessione e non trasversali
alle istruzioni.
Comunque, ho un oggetto che mi esegue query, nel cui costruttore
inserisco la connessione al db, che mi viene chiusa SEMPRE prima di
passare il controllo al metodo chiamante. La cosa piu' strana che
faccio e' chiamare, una volta reperita la connessione, un metodo e
passargli tale connessione. Il tutto sotto forma di transazioni. Non
so.. Tu come consigli di risolverla questa cosa??? Se serve posto del
codice.

 ha scritto nel messaggio 
news:1122300393....@g47g2000cwa.googlegroups.com...

Credo sia meglio..... evidentemente ho frainteso la tua situazione.
Scorpio.

Questo e' un'esempio di insert che effettuo.
  private static final String SELECT_CONTENTS =
      "SELECT * \n" +
        "FROM TABELLA T \n" +
       "WHERE T.PARAMETRO = ? \n"
      "ORDER BY COLONNA \n";
  public static DataContainer getUnionContents(
      String parametroSql,
      int begin,
      int end
  ) throws SQLException {
    Vector vParams = new Vector(1); // Parametri della query
    vParams.add( 0, parametroSql ); // Li assegno posizionalmente
    DataLink dl = new DataLink();   // Dichiaro l'oggetto che incapsula
la
                                    // connessione nel costruttore.
    /* Eseguo la query che mi rende un risultato sotto forma di
ArrayList di
     * HashMap (DataContainer).
     * begin ed end servono per gestire la paginazione del risultato.
*/
    DataContainer result =
dl.execQuery(SELECT_CONTENTS,vParams,begin,end);
    dl.release();
    return result;
  }
La classe DataLink incapsula alcuni metodi JDBC, se serve la posto
interamente, per il momento rendo il costruttore e i metodi usati:
  private void connect(){
		connessioniAperte++;
		resLog.info("Apro connessione Numero: " + connessioniAperte);
    Context    initContext = null;
    Context    envContext  = null;
    DataSource ds          = null;
    try{
      // Load the JDBC driver
      // Connect to the databse
//      sysLog.debug("Prelevo la connessione dal Pool to
:"+JNDI_KEY+ORACLE_KEY);
      initContext = new InitialContext();
      envContext  = (Context)initContext.lookup(JNDI_KEY);
      ds          = (DataSource)envContext.lookup(ORACLE_KEY);
      con         = ds.getConnection();
      /*
       * Imposta ad off l'autocommit di jdbc.
       * Il commit puo essere effettuato solo alla fine della procedura
per
       * lasciare la base dati consistente.
      */
      con.setAutoCommit(false);
//      sysLog.debug("Connected");
    } catch(SQLException e) {
//      sysLog.error("Impossibile stabilire una connessione");
//      sysLog.error("\tenvContext :\n"+envContext);
//      sysLog.error("\tinitContext:\n"+initContext);
//      sysLog.error("\tds         :\n"+ds);
      e.printStackTrace();
    } catch (NamingException e) {
//      sysLog.error("Cannot retrieve: "+JNDI_KEY+"/"+ORACLE_KEY);
      e.printStackTrace();
    }
//      sysLog.debug("DataLink.Connetti.con: "+con.toString() );
  }
  /**
   * Esegue una query e restituisce un DataContainer di @param limit
numero
   * massimo di righe. Se @param limit e' == -1, restituisce tutte le
righe
   * trovate.
   * */
  public DataContainer execQuery(String sql, Vector params, int begin,
int end)
      throws SQLException {
    sysLog.info("execSqlQuery:");
    sysLog.info("\tsql:\n\t"+sql);
    sysLog.info("\tparams:\n\t"+params);
    sysLog.info("\tbegin :\n\t"+begin);
    sysLog.info("\tend   :\n\t"+end);
    DataContainer result;
    PreparedStatement psQuery = con.prepareStatement(
        sql,
        ResultSet.TYPE_SCROLL_INSENSITIVE,
        ResultSet.CONCUR_READ_ONLY
    );
    for( int i = 0; i<params.size(); i++){
      Object o = params.get(i);
      if (o instanceof java.lang.String){
        psQuery.setString(i+1, (String)o);
      } else if (o instanceof java.lang.Integer){
        psQuery.setInt(i+1, ((Integer)o).intValue());
      } else if (o instanceof java.lang.Double){
        psQuery.setDouble(i+1, ((Double)o).doubleValue());
      } else if (o instanceof java.util.Date){
        psQuery.setDate(i+1,
DateUtil.dateToSqlDate((java.util.Date)o));
      } else if (o instanceof java.sql.Date){
        psQuery.setDate(i+1, (java.sql.Date)o);
      } else if (o==null){
        psQuery.setNull(i+1,java.sql.Types.VARCHAR);
      } else {
        psQuery.setString(i+1, o.toString());
      }
    }
    result = getDataContainer(psQuery.executeQuery(), begin, end);
    return result;
  }
/**
 * metodo per rilasciare la connessione in uso
 */
  public void release() {
    try {
      if (con != null) {
      	con.close();
	connessioniAperte--;
	resLog.info("Connessione chiusa Numero:"+connessioniAperte);
      }
	con = null;
    } catch (SQLException e)  {
    	resLog.error("Impossibile rilasciare la connessione numero:"
    	    + connessioniAperte,e);
    }
  }
Saluti,
Davide

       con.setAutoCommit(false);
[CUT]
Le transazioni sono gestite direttamente da WebSphere, per questo vien
fuori l'errore.
La storia che la connessione da un metodo passa ad un altro,
effettivamente esiste, ma solo negli EJB, perche' richiesto, come
dicevi, dagli standard J2EE. Nei metodi che referenziano JDBC invece,
WS non ha strumenti per gestire le connessioni aperte per errore. Ha
invece il potere di incazzarsi se setti autocommit a false, nella
connessione, perche' e' lui a volerle gestire.
Insomma mi e' bastato commentare la riga..
Saluti,
Davide Gurgone.


Prova a non chiudere una connessione in un metodo di una servlet. Vedrai che 
il container, che gestisce i thread, ne eseguirą il rollback. Inoltre se usi 
come ho visto che correttamente fai un pool di connessioni, WS ha tutte le 
informazioni che vuole per tracciare le connessioni (uso, tempo di utilizzo, 
thread che ha ottenuto la connessione etc).
Scorpio.

mmm provero'...