Cerrar conexiones JDBC en grupo

109

Nuestra sección de código estándar para usar JDBC es ...

Connection conn = getConnection(...);
Statement  stmt = conn.conn.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_READ_ONLY);
ResultSet  rset = stmt.executeQuery (sqlQuery);

// do stuff with rset

rset.close(); stmt.close(); conn.close();

Pregunta 1: Al usar el grupo de conexiones, ¿se debe cerrar la conexión al final? Si es así, ¿no se pierde el propósito de la agrupación? Y si no es así, ¿cómo sabe el origen de datos cuándo se libera una instancia particular de Connection y se puede reutilizar? Estoy un poco confundido en este caso, se agradecen los consejos.

Pregunta 2: ¿El siguiente método se acerca al estándar? Parece un intento de obtener una conexión desde el grupo, y si no se puede establecer DataSource, use el DriverManager antiguo. Ni siquiera estamos seguros de qué parte se está ejecutando en tiempo de ejecución. Repitiendo la pregunta anterior, ¿debería uno cerrar la conexión que surge de dicho método?

Gracias, - MS.

synchronized public Connection getConnection (boolean pooledConnection)
                                                        throws SQLException {
        if (pooledConnection) {
                if (ds == null) {
                        try {
                                Context envCtx = (Context)
                                        new InitialContext().lookup("java:comp/env");
                                ds = (DataSource) envCtx.lookup("jdbc/NamedInTomcat");
                                return ds.getConnection();
                        } catch (NamingException e) {
                                e.printStackTrace();
                }}
                return (ds == null) ? getConnection (false) : ds.getConnection();
        }
        return DriverManager.getConnection(
                "jdbc:mysql://"+ipaddy+":"+dbPort +"/" + dbName, uName, pWord);
}

Editar: creo que estamos obteniendo la conexión agrupada ya que no vemos un seguimiento de pila.

Manidip Sengupta
fuente

Respuestas:

121

Cuando se usa el grupo de conexiones, ¿se debe cerrar la conexión al final? Si es así, ¿no se pierde el propósito de la agrupación? Y si no es así, ¿cómo sabe el origen de datos cuándo se libera una instancia particular de Connection y se puede reutilizar? Estoy un poco confundido en este caso, se agradecen los consejos.

Sí, ciertamente también debe cerrar la conexión agrupada. En realidad, es un envoltorio de la conexión real. Debajo de las cubiertas se liberará la conexión real de regreso a la piscina. Es aún más hasta la piscina para decidir si la conexión real será en realidad ser cerrado o ser reutilizada para una nueva getConnection()llamada. Por lo tanto, independientemente de si está utilizando un grupo de conexiones o no, siempre debe cerrar todos los recursos JDBC en orden inverso en el finallybloque del trybloque donde los adquirió. En Java 7, esto se puede simplificar aún más mediante el uso de try-with-resourcesstatement.


¿El siguiente método se acerca al estándar? Parece un intento de obtener una conexión desde el grupo, y si no se puede establecer DataSource, use el DriverManager antiguo. Ni siquiera estamos seguros de qué parte se está ejecutando en tiempo de ejecución. Repitiendo la pregunta anterior, ¿debería uno cerrar la conexión que surge de dicho método?

El ejemplo da bastante miedo. Solo necesita buscar / inicializar DataSourceuna única vez durante el inicio de la aplicación en algún constructor / inicialización de una clase de configuración de base de datos en toda la aplicación. Luego, simplemente llame getConnection()a la misma fuente de datos durante el resto de la vida útil de la aplicación. Sin necesidad de sincronización ni comprobaciones nulas.

Ver también:

BalusC
fuente
Eso es lo que está haciendo (inicializar una vez), ¿no? ds es una variable de instancia, y if (ds == null) ... es la parte de inicialización.
Manidip Sengupta
Hacer las comprobaciones cada vez en un método de obtención como getConnection()es extraño. Simplemente hágalo en c'tor o bloque de inicialización de la misma clase, sin sincronización / nulos. Solo se llamará una vez. Para obtener más sugerencias y ejemplos iniciales, este artículo puede resultarle útil.
BalusC
Excelente artículo, BalusC. La clase con la que estoy tratando implementa prácticamente la capa de datos, utilizando DTO. Estoy de acuerdo contigo, la inicialización debería estar en constructor. Ahora, esta clase tiene un montón de métodos, cada uno con conn, stmt y rset como variables locales, las conexiones están en un bloque try, y finalmente hay una llamada de 1 línea csrClose (conn, stmt, rset), donde los 3 están cerrados (en orden inverso). Ahora, el DTO que desarrolla en el ejemplo es una imagen reflejada de una fila de la tabla DB. Tenemos consultas SQL complejas con uniones (y otras cláusulas), ¿tiene un artículo sobre cómo desarrollar DAO para obtener tales resultados?
Manidip Sengupta
2
@yat: DEBE llamarlos close()a todos en el finallybloque del mismo trybloque donde los adquirió / creó. Esto es completamente independientemente de si se trata de una conexión agrupada o no.
BalusC
1
@iJava: ese grupo está escrito por un aficionado que no tiene idea de lo que está haciendo. Ignóralo y busca una biblioteca real. Por ejemplo, HikariCP.
BalusC
22

Las agrupaciones normalmente le devuelven un objeto Connection envuelto, donde se anula el método close (), y normalmente devuelve la conexión a la agrupación. Llamar a close () está bien y probablemente aún sea necesario.

Un método close () probablemente se vería así:

public void close() throws SQLException {
  pool.returnConnection(this);
}

Para su segunda pregunta, puede agregar un registrador para mostrar si el bloque inferior se ejecuta alguna vez. Me imagino que solo querría una forma u otra para la configuración de las conexiones de su base de datos. Solo usamos un grupo para nuestros accesos a la base de datos. De cualquier manera, cerrar la conexión sería muy importante para evitar fugas.

taer
fuente
Estoy de acuerdo, tenemos un registrador y eso también podría usarse aquí. Necesito estudiar un poco sobre cómo puede envolver un objeto, anular su método close () pero aún mantener el mismo nombre de clase (Conexión)
Manidip Sengupta
1
Calling close() is OK and probably still required., no llamar a cerrar filtrará la conexión, a menos que el grupo implemente alguna estrategia de recuperación
svarog
0

En realidad, el mejor enfoque para la gestión de conexiones es no distribuirlas en ningún código en ningún lugar.

Cree una clase SQLExecutor que sea la única ubicación que abre y cierra conexiones.

El resto de la aplicación luego bombea declaraciones al ejecutor en lugar de obtener conexiones del grupo y administrarlas (o administrarlas mal) por todas partes.

Puede tener tantas instancias del ejecutor como desee, pero nadie debería escribir código que abra y cierre conexiones en su propio nombre.

Convenientemente, esto también le permite registrar todo su SQL desde un solo conjunto de código.

Rodney P. Barbati
fuente