Depois de usar o Hibernate na maioria dos meus projetos há cerca de 8 anos, entrei em uma empresa que desencoraja seu uso e deseja que os aplicativos interajam apenas com o banco de dados através de procedimentos armazenados.
Depois de fazer isso por algumas semanas, não consegui criar um modelo de domínio avançado do aplicativo que estou começando a criar, e o aplicativo parece um script transacional (horrível).
Alguns dos problemas que encontrei são:
- Não é possível navegar no gráfico de objetos, pois os procedimentos armazenados apenas carregam a quantidade mínima de dados, o que significa que, às vezes, temos objetos semelhantes com campos diferentes. Um exemplo é: temos um procedimento armazenado para recuperar todos os dados de um cliente e outro para recuperar informações da conta, além de alguns campos do cliente.
- Muita lógica acaba nas classes auxiliares, portanto o código se torna mais estruturado (com entidades usadas como estruturas C antigas).
- Código de andaime mais chato, pois não existe uma estrutura que extraia conjuntos de resultados de um procedimento armazenado e o coloque em uma entidade.
Minhas perguntas são:
- alguém já passou por uma situação semelhante e não concordou com a abordagem do procedimento de armazenamento? o que você fez?
- Existe um benefício real do uso de procedimentos armazenados? além do ponto bobo de "ninguém pode emitir uma tabela suspensa".
- Existe uma maneira de criar um domínio rico usando procedimentos armazenados? Eu sei que existe a possibilidade de usar o AOP para injetar DAOs / Repositórios em entidades para poder navegar no gráfico de objetos. Não gosto dessa opção, pois é muito próxima do vodu.
Conclusão
Primeiro, obrigado a todos por suas respostas. A conclusão que cheguei é que os ORMs não permitem a criação de modelos Rich Domain (como algumas pessoas mencionaram), mas simplificam a quantidade de trabalho (geralmente repetitivo). A seguir, é apresentada uma explicação mais detalhada da conclusão, mas não é baseada em dados concretos.
A maioria dos aplicativos solicita e envia informações para outros sistemas. Para fazer isso, criamos uma abstração nos termos do modelo (por exemplo, um evento de negócios) e o modelo de domínio envia ou recebe o evento. O evento geralmente precisa de um pequeno subconjunto de informações do modelo, mas não de todo o modelo. Por exemplo, em uma loja online, um gateway de pagamento solicita algumas informações e o total para cobrar um usuário, mas não exige o histórico de compras, os produtos disponíveis e toda a base de clientes. Portanto, o evento possui um conjunto pequeno e específico de dados.
Se considerarmos o banco de dados de um aplicativo como um sistema externo, precisamos criar uma abstração que permita mapear as entidades do Modelo de Domínio para o banco de dados ( como NimChimpsky mencionou , usando um mapeador de dados). A diferença óbvia é que agora precisamos criar um mapeamento para cada entidade de modelo no banco de dados (um esquema herdado ou procedimentos armazenados), com a dor extra de que, como os dois não estão sincronizados, uma entidade de domínio pode mapear parcialmente para uma entidade de banco de dados (por exemplo, uma classe UserCredentials que contém apenas nome de usuário e senha é mapeada para uma tabela Usuários que possui outras colunas) ou uma entidade de modelo de domínio pode mapear para mais de uma entidade de banco de dados (por exemplo, se houver uma um mapeamento na tabela, mas queremos todos os dados em apenas uma classe).
Em um aplicativo com poucas entidades, a quantidade de trabalho extra pode ser pequena se não houver necessidade de transversalidade das entidades, mas aumenta quando há uma necessidade condicional de transversalidade das entidades (e, portanto, podemos implementar algum tipo de 'preguiçoso'). Carregando'). À medida que um aplicativo cresce para ter mais entidades, esse trabalho apenas aumenta (e eu tenho a sensação de que aumenta não linearmente). Minha suposição aqui é que não tentamos reinventar um ORM.
Um benefício de tratar o banco de dados como um sistema externo é que podemos codificar situações nas quais queremos 2 versões diferentes de um aplicativo em execução, nas quais cada aplicativo possui um mapeamento diferente. Isso se torna mais interessante no cenário de entregas contínuas para produção ... mas acho que isso também é possível com ORMs em menor grau.
Vou descartar o aspecto de segurança, com base em que um desenvolvedor, mesmo que ele não tenha acesso ao banco de dados, pode obter a maioria, senão todas as informações armazenadas em um sistema, apenas injetando código malicioso (por exemplo, Não acredito que esqueci de remover a linha que registra os detalhes do cartão de crédito dos clientes, prezado senhor! ).
Pequena atualização (6/6/2012)
Os procedimentos armazenados (pelo menos no Oracle) impedem fazer algo como entrega contínua com tempo de inatividade zero, pois qualquer alteração na estrutura das tabelas invalidará os procedimentos e acionadores. Portanto, durante o tempo em que o banco de dados está sendo atualizado, o aplicativo também ficará inativo. A Oracle fornece uma solução para essa redefinição baseada em edição , mas os poucos DBAs que perguntei sobre esse recurso mencionaram que ele estava mal implementado e não o colocaram em um banco de dados de produção.
Respostas:
Seu aplicativo ainda deve ser modelado a partir dos princípios de design orientados a domínio. Se você usa um ORM, JDBC direto, chamar SPs (ou qualquer outra coisa) não deve importar . Espero que uma camada fina abstraia seu modelo dos SPs faça o truque neste caso. Como outro cartaz afirmou , você deve exibir os SPs e seus resultados como um serviço e mapear os resultados para o seu modelo de domínio.
fonte
No mundo financeiro (e nos locais onde a conformidade com Sarbanes-Oxley é necessária), você deve poder auditar os sistemas para garantir que eles façam o que deveriam. Nesses casos, é muito mais fácil garantir a conformidade quando todo o acesso a dados é realizado através de procedimentos armazenados. E quando todo o SQL ad-hoc é removido, é muito mais difícil ocultar as coisas. Para um exemplo de por que isso seria uma "coisa boa", refiro-o ao artigo clássico de Ken Thompson, Reflections on Trusting Trust .
fonte
Os procedimentos armazenados são muito mais eficientes que o código SQL do lado do cliente. Eles pré-compilam o SQL no banco de dados, o que também permite realizar algumas otimizações.
Arquitetonicamente, um SP retornará os dados mínimos necessários para uma tarefa, o que é bom, pois significa que menos dados estão sendo transferidos. Se você tem essa arquitetura, precisa pensar no DB como um serviço (pense nele como um serviço da Web e cada SP é um método para chamar). Não deve ser um problema trabalhar com isso dessa maneira, enquanto um ORM o orienta a trabalhar com dados remotos como se fossem locais, o que o leva a introduzir problemas de desempenho se você não for cuidadoso.
Já estive em situações em que usamos SPs completamente, o banco de dados forneceu uma API de dados e a usamos. Esse aplicativo em particular era de escala muito grande e apresentava um desempenho incrível. Depois disso, não terei nada de ruim sobre SPs!
Há outra vantagem - os DBAs gravam todas as suas consultas SQL para você e lidam com toda a hierarquia relacional no banco de dados, para que você não precise.
fonte
the approach of letting the DBAs write the procedures smells like development silos
+100 internets para você por essa jóia da verdade. Eu sempre vi isso como o caso em que o acesso aos dados era controlado por meio de procedimentos armazenados.O que acontece com frequência é que os desenvolvedores usam incorretamente seus objetos ORM como modelos de domínio.
Isso está incorreto e vincula seu domínio diretamente ao seu esquema de banco de dados.
O que realmente deveria ter são modelos de domínio separados, tão ricos quanto você quiser e usar a camada ORM separadamente.
Isso significa que você precisará mapear entre cada conjunto de objetos.
fonte
Os objetos do seu domínio podem ser preenchidos da maneira que desejar, não é necessário usar o Hibernate. Eu acho que o termo apropriado é mapeador de dados . É bem possível que seus dados persistentes sejam uma estrutura completamente diferente dos objetos do seu domínio.
fonte