Uso de SQL en ciclo de vida de un servlet

Buen día, el día de hoy estaba leyendo un tutorial sobre servlets y en la sección de uso del JDBC, vi que la iniciación de la conexión hasta el createStatement estaban en el método init del servlet, y el cierre de la conexión y del statement estaban en el método destroy del mismo servlet, ahora mis preguntas:

¿Esto es standar?

¿Existe un problema si hago todo este proceso en el processrequest?

¿Influye en mi aplicación en que parte del servlet cierre o abra mi conexion, así como el control de excepciones?

¿Es necesario cerrar el stamenet, preparedstament y resulset (una ves leí que no era necesario, pero ahora ya tengo esta duda) en un bloque finally?

De antemano 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 ezamudio

no

Eso está mal, porque genera muchos problemas. Si la conexión y el statement se crean en el init, es porque se guardan como parte del estado del servlet, y tanto la conexión como el statement deben ser utilizados por un solo hilo a la vez. Cuando haya peticiones concurrentes, ese servlet va a tronar de manera impredecible.

Para contestar las preguntas de manera muy puntual:

No es estándar.

De hecho es mejor si haces todo eso en el processRequest, usando puras variables locales. Lo que sí podrías tener como estado en el servlet es un DataSource, y que al configurar el servlet ese DataSource sea un pool de conexiones.

Claro que influye dónde abres y cierras la conexión y el control de excepciones.

Sí, necesitas cerrar TODO: en el caso de un query, primero el resultSet, luego el statement, y al final la conexión. En tres bloques de hecho:

Connection conn = null;
try {
  conn = //obtener conexion
  PreparedStatement stmt = null;
  try {
    stmt = //preparar el statement
    ResultSet rs = stmt.executeQuery();
    try {
      while (rs.next()) {
        blabla
      }
    } finally {
      rs.close();
    }
  } finally {
    if (stmt != null) stmt.close();
  }
} finally {
  if (conn != null) conn.close();
}
Imagen de zlatan

Gracias por la respuesta

Más claro imposible, ya tenia varios proyectos escolares con jsp/servlets pero no tenia estos hábitos, muchas gracias, aunque cero que ya es tiempo de pasar a algún framewrok.

Una alternativa a los tres

Una alternativa a los tres bloques que puso @ezamudio es:

Connection conn        = null;
PreparedStatement stmt = null;
ResultSet rs           = null;
try {
   conn = obtenerConexion()
   stmt = prepararStatement()
   rs   = stmt.executeQuery();
   while (rs.next()) {
        blabla
    }
   conn.commit();
} catch( SQLException e ) {
    conn.rollback();
    throw e; // no me acuerdo si se puede o no
    // si no se puede entonces encadenar con otra
} finally {
    close( rs, stmt, connection );
}

Es decir, un solo finally y agregar este método ( que puede ser de clase y estar en una utilería )

public static void close( Resultset rs, PreparedStatement pstmt, Connection c )  throws SQLException {
    SQLException tt = null;
    if ( rs != null )  try {
        rs.close();
     } catch( SQLException e )  {
        tt = e;
    }
    if ( pstmt != null ) try  {
       pstmt.close();
    } catch (  SQLException e ) {
        tt = e;
    }
    if ( c != null ) try {
      c.close();
    } catch( SQLException e ) {
      tt = e;
    }
    if ( tt != null ) {
       throw tt;
    }
}  

Que es básicamente lo mismo, pero al obtener un método así se limpia más el código y mejora la lectura y mantenibilidad del software.

La documentación dice que al cerrar un PreparedStatement el Resulset se cierra automáticamente. También dice que al cerrar una conexión todos sus recursos se liberan, sin embargo puede ser que te encuentres un driver de JDBC que no cumpla con esto ( sería raro ) y lo que tienes que hacer es cerrarlos explicitamente.

También dice que la aplicación debe de explicitamente darle commit y/o rollback a la transacción al cerrar la conexion.

Por cierto, desde Java 7, se

Por cierto, desde Java 7, se puede utilizar la construcción "try with resources", por lo que la construcción anterior sería:

try (
    Connection conn        = obtenerConexion();
    PreparedStatement stmt = prepararElStatement( someDataHere);
    ResultSet rs           = stmt.executeQuery();
 ) {
   while ( rs.next() ) {
        blabla
    }
   conn.commit();
} catch ( SQLException e )  {
    conn.rollback();
    throw e;
}

Dadaaaa!! y no necesita el método feo ese de utilería. Java vuelve a ser bonito de nuevo \o/ :P y es exactamente lo mismo que puso @ezamudio el principio. Claro, necesitas un driver listo para Java 7 :(

pd Si alguien hace esto postee para ver como le fue :)