Después de usar Hibernate en la mayoría de mis proyectos durante aproximadamente 8 años, llegué a una empresa que desalienta su uso y quiere que las aplicaciones solo interactúen con la base de datos a través de procedimientos almacenados.
Después de hacer esto durante un par de semanas, no he podido crear un modelo de dominio rico de la aplicación que estoy comenzando a compilar, y la aplicación solo parece un script transaccional (horrible).
Algunos de los problemas que he encontrado son:
- No se puede navegar por el gráfico de objetos, ya que los procedimientos almacenados solo cargan la cantidad mínima de datos, lo que significa que a veces tenemos objetos similares con diferentes campos. Un ejemplo es: tenemos un procedimiento almacenado para recuperar todos los datos de un cliente, y otro para recuperar la información de la cuenta, además de algunos campos del cliente.
- Gran parte de la lógica termina en clases auxiliares, por lo que el código se vuelve más estructurado (con entidades utilizadas como estructuras de C antiguas).
- Código de andamio más aburrido, ya que no hay un marco que extraiga conjuntos de resultados de un procedimiento almacenado y lo coloque en una entidad.
Mis preguntas son:
- ¿Alguien ha estado en una situación similar y no estuvo de acuerdo con el enfoque del procedimiento de la tienda? ¿Qué hiciste?
- ¿Existe un beneficio real de usar procedimientos almacenados? aparte del punto tonto de "nadie puede emitir una tabla desplegable".
- ¿Hay alguna manera de crear un dominio rico utilizando procedimientos almacenados? Sé que existe la posibilidad de utilizar AOP para inyectar DAO / repositorios en entidades para poder navegar por el gráfico de objetos. No me gusta esta opción, ya que está muy cerca del vudú.
Conclusión
Primero, gracias a todos por sus respuestas. La conclusión a la que he llegado es que los ORM no permiten la creación de modelos de dominio enriquecido (como algunas personas mencionaron), pero sí simplifica la cantidad de trabajo (a menudo repetitivo). La siguiente es una explicación más detallada de la conclusión, pero no se basa en ningún dato sólido.
La mayoría de las aplicaciones solicitan y envían información a otros sistemas. Para hacer esto, creamos una abstracción en los términos del modelo (por ejemplo, un evento de negocios) y el modelo de dominio envía o recibe el evento. El evento generalmente necesita un pequeño subconjunto de información del modelo, pero no todo el modelo. Por ejemplo, en una tienda en línea, una pasarela de pago solicita cierta información del usuario y el total para cobrar a un usuario, pero no requiere el historial de compras, los productos disponibles y toda la base de clientes. Por lo tanto, el evento tiene un conjunto pequeño y específico de datos.
Si tomamos la base de datos de una aplicación como un sistema externo, entonces necesitamos crear una abstracción que nos permita mapear las entidades del Modelo de Dominio a la base de datos ( como mencionó NimChimpsky , usando un mapeador de datos). La diferencia obvia es que ahora necesitamos crear una asignación para cada entidad modelo a la base de datos (ya sea un esquema heredado o procedimientos almacenados), con el dolor adicional de que, dado que los dos no están sincronizados, una entidad de dominio podría mapearse parcialmente a una entidad de base de datos (por ejemplo, una clase de UserCredentials que solo contiene nombre de usuario y contraseña se asigna a una tabla de Usuarios que tiene otras columnas), o una entidad de modelo de dominio podría asignar a más de una entidad de base de datos (por ejemplo, si hay una una asignación en la tabla, pero queremos todos los datos en una sola clase).
En una aplicación con algunas entidades, la cantidad de trabajo adicional puede ser pequeña si no hay necesidad de atravesar las entidades, pero aumenta cuando hay una necesidad condicional de atravesar las entidades (y, por lo tanto, podríamos querer implementar algún tipo de 'perezoso' cargando'). A medida que una aplicación crece para tener más entidades, este trabajo solo aumenta (y tengo la sensación de que aumenta de forma no lineal). Mi suposición aquí es que no intentamos reinventar un ORM.
Una ventaja de tratar la base de datos como un sistema externo es que podemos codificar situaciones en las que queremos que se ejecuten 2 versiones diferentes de una aplicación, en las que cada aplicación tiene una asignación diferente. Esto se vuelve más interesante en el escenario de entregas continuas a la producción ... pero creo que esto también es posible con ORM en menor medida.
Voy a descartar el aspecto de seguridad, sobre la base de que un desarrollador, incluso si no tiene acceso a la base de datos, puede obtener la mayoría, si no toda, la información almacenada en un sistema, simplemente inyectando código malicioso (p. Ej. ¡No puedo creer que olvidé eliminar la línea que registra los datos de la tarjeta de crédito de los clientes, querido señor! ).
Pequeña actualización (6/6/2012)
Los procedimientos almacenados (al menos en Oracle) evitan hacer algo como la entrega continua con tiempo de inactividad cero, ya que cualquier cambio en la estructura de las tablas invalidará los procedimientos y los desencadenantes. Por lo tanto, durante el tiempo que se actualiza la base de datos, la aplicación también estará inactiva. Oracle proporciona una solución para esta denominada Redefinición basada en la edición , pero los pocos DBA que he preguntado sobre esta característica mencionaron que estaba mal implícita y no la incluirían en una base de datos de producción.
Respuestas:
Su aplicación aún debe modelarse a partir de principios de diseño basados en dominio. Ya sea que use un ORM, JDBC directo, llamar a SP (o lo que sea) no debería importar . Con suerte, una capa delgada que abstraiga su modelo de los SP debería ser la solución en este caso. Como dijo otro póster , debe ver los SP y sus resultados como un servicio y asignar los resultados a su modelo de dominio.
fuente
En el mundo financiero (y lugares donde se requiere el cumplimiento de Sarbanes-Oxley ), debe poder auditar los sistemas para asegurarse de que hagan lo que se supone que deben hacer. En estos casos, es mucho más fácil garantizar el cumplimiento cuando todo el acceso a datos se realiza a través de procedimientos almacenados. Y cuando se elimina todo el SQL ad-hoc, es mucho más difícil ocultar cosas. Para ver un ejemplo de por qué esto sería algo "bueno", lo remito al artículo clásico de Ken Thompson, Reflexiones sobre confiar en la confianza .
fuente
Los procedimientos almacenados son mucho más eficientes que el código SQL del lado del cliente. Precompilan SQL en la base de datos, lo que también le permite realizar algunas optimizaciones.
Arquitectónicamente, un SP devolverá los datos mínimos necesarios para una tarea, lo cual es bueno ya que significa que se están transfiriendo menos datos. Si tiene esa arquitectura, debe pensar en la base de datos como un servicio (piense en ella como un servicio web y cada SP es un método para llamar). Trabajar de esta manera no debería ser un problema, mientras que un ORM lo guía a trabajar con datos remotos como si fuera local, por lo que lo engañará para que presente problemas de rendimiento si no tiene cuidado.
He estado en situaciones en las que usamos SP por completo, el DB proporcionó una API de datos y la usamos. Esa aplicación en particular era muy grande y funcionó increíblemente bien. ¡No tendré nada malo que decir sobre los SP después de eso!
Hay otra ventaja: los DBA escribirán todas sus consultas SQL por usted y manejarán con gusto toda la jerarquía relacional en la base de datos, por lo que no tiene que hacerlo.
fuente
the approach of letting the DBAs write the procedures smells like development silos
+100 te conecta por esta joya de la verdad. Siempre he visto esto como el caso en el que el acceso a los datos se controlaba mediante procedimientos almacenados.Lo que sucede a menudo es que los desarrolladores usan incorrectamente sus objetos ORM como sus modelos de dominio.
Esto es incorrecto y vincula su dominio directamente a su esquema de base de datos.
Lo que realmente debería tener es modelos de dominio separados tan ricos como quieras y usar la capa ORM por separado.
Esto significa que necesitará un mapeo entre cada conjunto de objetos.
fuente
Los objetos de su dominio se pueden completar de la forma que desee, no es necesario utilizar Hibernate. Creo que el término apropiado es mapeador de datos . Es muy posible que sus datos persistentes tengan una estructura completamente diferente a los objetos de su dominio.
fuente