Tenemos un sistema mediante el cual la conexión de la base de datos se obtiene una vez usando un método común y se pasa a través de la clase relevante que se utilizará. Hay dudas de que pasar la conexión de la base de datos como un parámetro a diferentes clases podría causar problemas, así que verifico aquí para ver si esto es realmente viable, y ¿hay algún patrón mejor para hacerlo?
Sé que hay algunas herramientas ORM para hacer la persistencia, pero aún no podemos entrar en eso ...
Cualquier comentario es bienvenido, gracias.
java
database
patterns-and-practices
ipohfly
fuente
fuente
Respuestas:
Sí, es seguro pasar una conexión. Maneja la conexión en un bloque de control externo. No hay nada inseguro al respecto.
Lo que no es seguro es escribir código que no garantice que la conexión se elimine de manera oportuna. Olvidar limpiar un recurso no está relacionado con pasarlo. Podrías escribir fácilmente un código que deja una conexión suspendida sin pasarlo a ningún lado.
En C ++, está protegido por RAII si asigna en la pila o utiliza punteros inteligentes. En C # establezca una regla estricta para que todos los objetos desechables (como las conexiones) se declaren en un bloque "en uso". En Java, limpie con la lógica try-finally. Tenga revisiones de código en todo el código de capa de datos para garantizar esto.
El caso de uso más común es cuando tiene varias operaciones que se pueden combinar en muchas permutaciones. Y cada una de estas permutaciones debe ser una transacción atómica (todas tienen éxito o retroceden). entonces debe pasar la transacción (y por lo tanto la conexión correspondiente) a todos los métodos.
Supongamos que tenemos muchas acciones foobar () que se pueden combinar de varias maneras como transacciones atómicas.
Por cierto, querrá abrir las conexiones lo más tarde posible, deséchelas lo antes posible. Sus compañeros de equipo podrían tener razón si está tratando las conexiones como miembros del objeto, presentándolas como un estado innecesario y dejando las conexiones abiertas mucho más tiempo del necesario. Pero el acto de pasar una conexión o transacción como parámetro no es inherentemente incorrecto.
Por cierto. Dependiendo del soporte de su idioma para funciones de primera clase, puede realizar una lista de acciones foobar (). Entonces, una función podría manejar todas las permutaciones de las acciones. Eliminando la duplicación del bloque de control externo para cada permutación.
fuente
Parece que buscas la inyección de dependencia . Es decir, la conexión agrupada se crea una vez y se inyecta donde sea necesario. Ciertamente, pasar la conexión a través de un parámetro de método es una forma de inyectar dependencia, pero un contenedor de IoC como Guice, PicoContainer o Spring es otra forma (más segura) de hacerlo.
El uso de DI significa que puede resumir perfectamente la lógica en torno a la creación, apertura, uso y cierre de la conexión, lejos de su lógica comercial central.
Spring JDBC y otros son otros ejemplos de cómo realizar este tipo de comportamiento para usted
fuente
Pasar cosas de la base de datos en lugar de cosas de datos puede generar problemas. En ese sentido, siempre que sea práctico, no pase una cosa de la base de datos a menos que se pueda garantizar la higiene adecuada de la base de datos.
El problema con pasar cosas de la base de datos es que puede ser descuidado. He visto más de un error en el código con alguien que pasa por una conexión de base de datos, que alguien luego toma un conjunto de resultados y lo guarda en un objeto local (el conjunto de resultados, todavía conectado a la base de datos) y luego ata un cursor en el base de datos durante un tiempo significativo. En otra instancia, alguien pasó un conjunto de resultados a otra persona (que luego se escondió) y luego el método que pasó el conjunto de resultados lo cerró (y la declaración) lo que provocó errores cuando otros métodos intentaron funcionar con el conjunto de resultados que ya no existía.
Todo esto se deriva de no respetar la base de datos, la conexión, la declaración, el conjunto de resultados y sus ciclos de vida.
Para evitar esto, existen patrones y estructuras existentes que funcionan mejor con las bases de datos y no tienen elementos de base de datos que necesitan salir de las clases en las que están confinados. Los datos entran, los datos salen, la base de datos permanece en su lugar.
fuente
Root
un Dao. Pero luego te das cuenta de que también quieres una forma de obtener unNode
sin sacar todo elRoot
objeto con él. ¿Cómo se hace que elRoot
Dao llame alNode
código de Dao (es decir: reutilizar), pero asegúrese de que elNode
Dao solo cierre la conexión cuandoNode
se llama directamente al Dao y mantenga la conexión abierta cuandoRoot
se llama al Dao?Pasar
Connection
instancias no suele ser un problema, aunque en la mayoría de las situaciones solo las implementaciones de DAO deberían tener algo que ver con ellas. Ahora, con el problema de que las conexiones no se cierran después de su uso, en realidad es fácil de solucionar: elConnection
objeto debe cerrarse al mismo nivel que se abre, es decir, con el mismo método. Yo personalmente uso el siguiente patrón de código:De esa manera me aseguro de que todas las conexiones estén siempre cerradas, incluso si se produce una excepción dentro del bloque. De hecho, uso el mismo patrón
Statement
eResultSet
instancias exactamente , y todo ha sido fácil hasta ahora.Editar 2018-03-29: Como lo indica el usuario 1156544 en los comentarios a continuación, comenzando con Java 7, se debe favorecer el uso de la construcción de prueba con recursos. Al usarlo, el patrón de código que proporcioné en mi respuesta inicial se puede simplificar así:
fuente
dataSource
lugar deDataSource
(arreglaré mi respuesta con respecto a ese punto). El tipo exacto de ese objeto seríajavax.sql.DataSource
. En el código anterior, solía tener un singleton que administrara todas las fuentes de datos disponibles dentro de mis aplicaciones. Mis DAO no tenían que saberlo, ya que laDataSource
instancia se proporciona mediante inyección de dependencia.Hay una compensación para hacer las cosas de esta manera en lugar de usar un singleton que puede obtener según sea necesario. He hecho cosas en ambos sentidos en el pasado.
En general, debe pensar en las consecuencias de la administración de la conexión de la base de datos, y esto puede o no ser ortogonal al uso de la consulta de la base de datos. Por ejemplo, si tiene una conexión db para una instancia de aplicación determinada y se cierra cuando no está en uso, eso sería ortogonal. Ponga la gestión en una clase singleton y no la pase. Esto le permite administrar la conexión db según lo necesite. Por ejemplo, si desea cerrar una conexión en cada confirmación (y volver a abrir en la próxima llamada), esto es más fácil de hacer en un singleton porque la API para esto se puede centralizar.
Por otro lado, suponga que necesita administrar un grupo de conexiones donde una llamada dada puede necesitar usar cualquier conexión arbitraria. Esto puede suceder cuando se realizan transacciones distribuidas en varios servidores, por ejemplo. En este caso, es mejor pasar el objeto de conexión db que trabajar con singletons. Creo que este suele ser el caso más raro, pero no hay nada de malo en hacerlo cuando sea necesario.
fuente