Numa situação hipotética, quero criar um sistema web de gestão hoteleira que será vendido para vários hotéis diferentes. Estou com dúvida em relação ao acesso ao banco de dados. Como ficaria essa situação? Cada hotel com seu banco de dados? O mesmo banco de dados para todos hotéis? Se cada hotel deverá ter seu próprio banco de dados, como fazer isso utilizando o hibernate sendo que o arquivo de configuração ‘hibernate.cfg.xml’ é estático e atualmente estou passando um nome de banco de dados específico?
Quem puder me ajudar, fico agradecido.
Cada WAR teria seu próprio hibernate.cfg.xml de configuração.
Eu vejo sempre que a melhor prática e cada um ter seu próprio banco. [=
Seguinte de uma pesquisada sobre “Multitenancy”, o hibernate suporta.
Existe basicamente 3 formas de fazer
1ª Cada cliente tem seu banco de dados;
2ª Cada cliente fica em um schema;
3ª Todas as tabelas tem um campo onde nele tem o código do cliente.
Como disse antes de uma pesquisada sobre o tema
Oi Jonas,
este é um dos problemas mais difíceis da computação atualmente: trata-se do problema da multi tenância (multi-tenant).
Há diversas soluções possíveis para o problema, que vão desde particionamento de tabelas (uma partição por cliente) até modelagens de dados mais complexas, chegando ao ponto de você ter uma instância do banco de dados por cliente.
Você vai ter de pensar em alguns pontos importantes na sua modelagem, como por exemplo a possibilidade de ter campos customizados por cliente na emissão de relatórios customizados.
Há outro ponto também importante a ser abordado: como cobrar. Você precisa montar o seu negócio de tal maneira que aqueles usuários que tenham maior demanda computacional paguem mais. Outro problema difícil.
Minha sugestão pra você neste momento é estudar tudo o que encontrar sobre multi-tenância.
Outro ponto importantíssimo: estude como calcular o seu custo operacional. É vital para o seu problema.
[quote=Hebert Coelho]Cada WAR teria seu próprio hibernate.cfg.xml de configuração.
Eu vejo sempre que a melhor prática e cada um ter seu próprio banco. [=[/quote]
Oi Herbert, isto eleva o seu custo operacional às alturas. Vai funcionar com dois, três clientes, mas a partir do quarto, quinto, fica tão caro manter as instâncias em execução que o custo por cliente se torna impraticável.
O ideal é ter o mínimo de JVMs em execução, porque a parte da memória compartilhada vai ser sempre gigantesca, mas a customizada mínima.
[quote=kicolobo][quote=Hebert Coelho]Cada WAR teria seu próprio hibernate.cfg.xml de configuração.
Eu vejo sempre que a melhor prática e cada um ter seu próprio banco. [=[/quote]
Oi Herbert, isto eleva o seu custo operacional às alturas. Vai funcionar com dois, três clientes, mas a partir do quarto, quinto, fica tão caro manter as instâncias em execução que o custo por cliente se torna impraticável.
O ideal é ter o mínimo de JVMs em execução, porque a parte da memória compartilhada vai ser sempre gigantesca, mas a customizada mínima. [/quote]Opa, blz?
Ou então fechar como em uma empresa que já trabalhei, cada empresa teria seu próprio servidor. [=
Outra opção seria utilizar nuvem, como o Jelastic que entra no tema de multi tenância.
Eu não afirmo que a minha seja a única opção, e apenas a que eu gosto mais. [=
[quote=Hebert Coelho]Cada WAR teria seu próprio hibernate.cfg.xml de configuração.
Eu vejo sempre que a melhor prática e cada um ter seu próprio banco. [=[/quote]
também vejo assim como você, porém hoje temos suporte a Multi-tenancy.
http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html/ch16.html
Sendo uma aplicação Web, se você está colocando as configurações de acesso ao banco no hibernate.cfg.xml isso está errado. O correto é configurar um data source no seu servidor e passar o nome do datasource na configuração do Hibernate.
Eu vejo duas maneiras de resolver o problema:
1 - Fazer um único banco de dados, com uma tabela HOTEL, sendo que cada linha de cada tabela vai precisar referenciar o hotel ao qual pertence (com exceção de tabelas como endereço, estado, etc.)
2 - Considerar que cada hotel terá seu próprio banco de dados. Nesse caso, eu também criaria uma instância do servidor de aplicação para cada hotel também. Pra falar a verdade, eu até acho essa maneira mais justa, pois eu não ia querer que o desempenho da minha aplicação se degradasse por conta de um concorrente.
O que eu definitivamente não faria seria fazer minha aplicação acessar vários banco de dados diferentes e ficar controlando isso pela aplicação. É bem provável que você teria que espalhar essa lógica pela aplicação inteira.
[quote=Hebert Coelho][quote=kicolobo][quote=Hebert Coelho]Cada WAR teria seu próprio hibernate.cfg.xml de configuração.
Eu vejo sempre que a melhor prática e cada um ter seu próprio banco. [=[/quote]
Oi Herbert, isto eleva o seu custo operacional às alturas. Vai funcionar com dois, três clientes, mas a partir do quarto, quinto, fica tão caro manter as instâncias em execução que o custo por cliente se torna impraticável.
O ideal é ter o mínimo de JVMs em execução, porque a parte da memória compartilhada vai ser sempre gigantesca, mas a customizada mínima. [/quote]Opa, blz?
Ou então fechar como em uma empresa que já trabalhei, cada empresa teria seu próprio servidor. [=
Outra opção seria utilizar nuvem, como o Jelastic que entra no tema de multi tenância.
Eu não afirmo que a minha seja a única opção, e apenas a que eu gosto mais. [=[/quote]
Opa Herbert, com certeza. A sua solução é a mais simples de implementar, o problema é isto que mencionei acima: o custo vai ficar bastante elevado. A grande questão é: pra que 10 JVMs se eu posso solucionar o problema com 1 ou 2 (chutando números)?
Nestes casos, uma alternativa que levo em consideração sabe qual é? Não usar Hibernate. Really: usar JDBC direto pra poder otimizar as consultas por cliente e pensar sériamente em uma solução que envolva bancos de dados NoSQL.
Uma base documental por exemplo resolve na hora grande parte do problema dos campos complementares por cliente. Estou desenvolvendo um produto agora que lida justamente com este problema de multitenancia. O grande problema está sendo o custo: nestes casos, cada bit conta, cada ciclo conta. Por isto, quanto mais “próximo ao metal” você estiver, mais fácil fica evitar problemas.
[quote=kicolobo]Opa Herbert, com certeza. A sua solução é a mais simples de implementar, o problema é isto que mencionei acima: o custo vai ficar bastante elevado. A grande questão é: pra que 10 JVMs se eu posso solucionar o problema com 1 ou 2 (chutando números)?
Nestes casos, uma alternativa que levo em consideração sabe qual é? Não usar Hibernate. Really: usar JDBC direto pra poder otimizar as consultas por cliente e pensar sériamente em uma solução que envolva bancos de dados NoSQL.
Uma base documental por exemplo resolve na hora grande parte do problema dos campos complementares por cliente. Estou desenvolvendo um produto agora que lida justamente com este problema de multitenancia. O grande problema está sendo o custo: nestes casos, cada bit conta, cada ciclo conta. Por isto, quanto mais “próximo ao metal” você estiver, mais fácil fica evitar problemas.[/quote]Claro! Concordo com você. É tudo uma questão de calcular custos e análise do contrato estabelecido.
Apenas sou pé atras até o quanto o JPA seria pior que JDBC puro (O Batoo, por exemplo, é uma implementação que afirma ser até 15x mais performático que o Hibernate :shock: Nisso me pergunto quão longe estaria da performance com JDBC puro).
[quote=Hebert Coelho][quote=kicolobo]Opa Herbert, com certeza. A sua solução é a mais simples de implementar, o problema é isto que mencionei acima: o custo vai ficar bastante elevado. A grande questão é: pra que 10 JVMs se eu posso solucionar o problema com 1 ou 2 (chutando números)?
Nestes casos, uma alternativa que levo em consideração sabe qual é? Não usar Hibernate. Really: usar JDBC direto pra poder otimizar as consultas por cliente e pensar sériamente em uma solução que envolva bancos de dados NoSQL.
Uma base documental por exemplo resolve na hora grande parte do problema dos campos complementares por cliente. Estou desenvolvendo um produto agora que lida justamente com este problema de multitenancia. O grande problema está sendo o custo: nestes casos, cada bit conta, cada ciclo conta. Por isto, quanto mais “próximo ao metal” você estiver, mais fácil fica evitar problemas.[/quote]Claro! Concordo com você. É tudo uma questão de calcular custos e análise do contrato estabelecido.
Apenas sou pé atras até o quanto o JPA seria pior que JDBC puro (O Batoo, por exemplo, é uma implementação que afirma ser até 15x mais performático que o Hibernate :shock: Nisso me pergunto quão longe estaria da performance com JDBC puro). [/quote]
Oi Herbert,
é, com relação à performance, vai ser caso a caso. Na maior parte das vezes o JPA/Hibernate vai ser mais rápido por duas razões:
- As consultas muitas vezes são geradas otimizadas e de forma melhor que as geradas manualmente (normalmente aí a culpa fica mais por conta do programador do que vantagem pro JPA)
- As estratégias de cacheamento feitas de maneira automatizada.
Nos dois casos, você ganha muito em produtividade. Mas quando precisa estar mais próximo do SGBD, JDBC ainda impera. Outro ponto importante neste caso é que normalmente o custo de memória vai ser menor, porque é menos coisa pra carregar também. Claro: entra aí o fardo da sua perda de produtividade, mas como disse, cada caso é único.
O que observo é que quando estou no JDBC nativo eu consigo atuar mais diretamente em cima das minhas estratégias de multi tenancia e, nestes casos, eu ganho em produtividade com relação ao JPA (não preciso ficar pensando em como o mapeamento vai ser traduzido pra JDBC por exemplo). Além disto, posso também (ao custo da portabilidade) ganhar alguma coisa usando recursos nativos do SGBD que tiver adotado na solução.
Agora, falando a respeito da minha experiência profissional: JDBC sempre foi nos projetos que atuei ordens de magnitude mais performático que qualquer solução ORM.
E se você conseguir separar BEM dados de algoritmos, ao invés de fazer aquelas maluquices com zilhões de entidades sendo instanciadas - o erro mais comum ao adotarmos um ORM - man… Você consegue tirar muito mais ciclo por real investido.
[quote=kicolobo][quote=Hebert Coelho][quote=kicolobo]Opa Herbert, com certeza. A sua solução é a mais simples de implementar, o problema é isto que mencionei acima: o custo vai ficar bastante elevado. A grande questão é: pra que 10 JVMs se eu posso solucionar o problema com 1 ou 2 (chutando números)?
Nestes casos, uma alternativa que levo em consideração sabe qual é? Não usar Hibernate. Really: usar JDBC direto pra poder otimizar as consultas por cliente e pensar sériamente em uma solução que envolva bancos de dados NoSQL.
Uma base documental por exemplo resolve na hora grande parte do problema dos campos complementares por cliente. Estou desenvolvendo um produto agora que lida justamente com este problema de multitenancia. O grande problema está sendo o custo: nestes casos, cada bit conta, cada ciclo conta. Por isto, quanto mais “próximo ao metal” você estiver, mais fácil fica evitar problemas.[/quote]Claro! Concordo com você. É tudo uma questão de calcular custos e análise do contrato estabelecido.
Apenas sou pé atras até o quanto o JPA seria pior que JDBC puro (O Batoo, por exemplo, é uma implementação que afirma ser até 15x mais performático que o Hibernate :shock: Nisso me pergunto quão longe estaria da performance com JDBC puro). [/quote]
Oi Herbert,
é, com relação à performance, vai ser caso a caso. Na maior parte das vezes o JPA/Hibernate vai ser mais rápido por duas razões:
- As consultas muitas vezes são geradas otimizadas e de forma melhor que as geradas manualmente (normalmente aí a culpa fica mais por conta do programador do que vantagem pro JPA)
- As estratégias de cacheamento feitas de maneira automatizada.
Nos dois casos, você ganha muito em produtividade. Mas quando precisa estar mais próximo do SGBD, JDBC ainda impera. Outro ponto importante neste caso é que normalmente o custo de memória vai ser menor, porque é menos coisa pra carregar também. Claro: entra aí o fardo da sua perda de produtividade, mas como disse, cada caso é único.
O que observo é que quando estou no JDBC nativo eu consigo atuar mais diretamente em cima das minhas estratégias de multi tenancia e, nestes casos, eu ganho em produtividade com relação ao JPA (não preciso ficar pensando em como o mapeamento vai ser traduzido pra JDBC por exemplo). Além disto, posso também (ao custo da portabilidade) ganhar alguma coisa usando recursos nativos do SGBD que tiver adotado na solução.
Agora, falando a respeito da minha experiência profissional: JDBC sempre foi nos projetos que atuei ordens de magnitude mais performático que qualquer solução ORM.
E se você conseguir separar BEM dados de algoritmos, ao invés de fazer aquelas maluquices com zilhões de entidades sendo instanciadas - o erro mais comum ao adotarmos um ORM - man… Você consegue tirar muito mais ciclo por real investido.[/quote]Opa, legal saber.
Mas… só uma pergunta em cima que você falou:[quote]O que observo é que quando estou no JDBC nativo eu consigo atuar mais diretamente em cima das minhas estratégias de multi tenancia e, nestes casos, eu ganho em produtividade com relação ao JPA (não preciso ficar pensando em como o mapeamento vai ser traduzido pra JDBC por exemplo). Além disto, posso também (ao custo da portabilidade) ganhar alguma coisa usando recursos nativos do SGBD que tiver adotado na solução.[/quote]E se você utilizasse native query? Funciona como sua query sendo disparada na linguagem nativa, não?
Valeu, obrigado por compartilhar. [=
Native Query do Hibernate nem sempre funciona como a gente quer.
Você tem de ficar esperto pra usar uma sessão sem estado quando for fazer isto, porque se usar com estado, é comum que o estado dos objetos em sessão seja atualizado ao executar SQL nativo (rola muito isto com Grails por exemplo). Consequentemente, todo o ganho de performance vai pro saco.
Além disto, um outro ponto importante pra lembrar é o seguinte: quando você vai usar native query via JPA/Hibernate, tá ainda passando por uma camada desnecessária, ao menos no meu ponto de vista. Pra que eu preciso dela se eu quero estar atuando direto no BD? Este é um questionamento interessante. Lembre-se que uma das vantagens do ORM é que ele mantém o estado de algumas entidades, tem de levar isto em consideração.
No geral, uma prática que costumo adotar com bastante sucesso é sempre pensar nas minhas entidades como objetos de curtíssima duração (normalmente apenas dentro da execução de um método). Isto me ajuda a evitar estes problemas que disse acima. Por outro lado, objetos com curta duração podem acabar com sua memória quando alto processamento ocorre, então… nestes casos, em que vou precisar de alta performance, sempre acabo voltando pro JDBC
[quote=kicolobo]Native Query do Hibernate nem sempre funciona como a gente quer.
Você tem de ficar esperto pra usar uma sessão sem estado quando for fazer isto, porque se usar com estado, é comum que o estado dos objetos em sessão seja atualizado ao executar SQL nativo (rola muito isto com Grails por exemplo). Consequentemente, todo o ganho de performance vai pro saco.
Além disto, um outro ponto importante pra lembrar é o seguinte: quando você vai usar native query via JPA/Hibernate, tá ainda passando por uma camada desnecessária, ao menos no meu ponto de vista. Pra que eu preciso dela se eu quero estar atuando direto no BD? Este é um questionamento interessante. Lembre-se que uma das vantagens do ORM é que ele mantém o estado de algumas entidades, tem de levar isto em consideração.
No geral, uma prática que costumo adotar com bastante sucesso é sempre pensar nas minhas entidades como objetos de curtíssima duração (normalmente apenas dentro da execução de um método). Isto me ajuda a evitar estes problemas que disse acima. Por outro lado, objetos com curta duração podem acabar com sua memória quando alto processamento ocorre, então… nestes casos, em que vou precisar de alta performance, sempre acabo voltando pro JDBC :)[/quote]Claro, concordo.
Mas tem que se lembrar de que, utilizar native query teria a vantagem de usar um mapeamento ORM o que aumenta a produção de código (imagine jogar o resultado de uma query para um objeto com 40 campos e 3 listas, como seria a produção que código). O cache do JPA pode ser desligado com uma configuração. E existem técnicas para melhorar uma pesquisa, por exemplo, não abrir transação ou anotar um método com @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) que não haverá objetos “attached” e outras.
Existem técnicas que realmente podem melhorar e deixar que o JPA seja otimizado de acordo com a necessidade, mas infelizmente não tenho a experiência de multi tenancy que você. Vou ficar atento a isso quando eu cair nesse cenário. [=
[quote=Hebert Coelho][quote=kicolobo]Native Query do Hibernate nem sempre funciona como a gente quer.
Você tem de ficar esperto pra usar uma sessão sem estado quando for fazer isto, porque se usar com estado, é comum que o estado dos objetos em sessão seja atualizado ao executar SQL nativo (rola muito isto com Grails por exemplo). Consequentemente, todo o ganho de performance vai pro saco.
Além disto, um outro ponto importante pra lembrar é o seguinte: quando você vai usar native query via JPA/Hibernate, tá ainda passando por uma camada desnecessária, ao menos no meu ponto de vista. Pra que eu preciso dela se eu quero estar atuando direto no BD? Este é um questionamento interessante. Lembre-se que uma das vantagens do ORM é que ele mantém o estado de algumas entidades, tem de levar isto em consideração.
No geral, uma prática que costumo adotar com bastante sucesso é sempre pensar nas minhas entidades como objetos de curtíssima duração (normalmente apenas dentro da execução de um método). Isto me ajuda a evitar estes problemas que disse acima. Por outro lado, objetos com curta duração podem acabar com sua memória quando alto processamento ocorre, então… nestes casos, em que vou precisar de alta performance, sempre acabo voltando pro JDBC :)[/quote]Claro, concordo.
Mas tem que se lembrar de que, utilizar native query teria a vantagem de usar um mapeamento ORM o que aumenta a produção de código (imagine jogar o resultado de uma query para um objeto com 40 campos e 3 listas, como seria a produção que código). O cache do JPA pode ser desligado com uma configuração. E existem técnicas para melhorar uma pesquisa, por exemplo, não abrir transação ou anotar um método com @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) que não haverá objetos “attached” e outras.
Existem técnicas que realmente podem melhorar e deixar que o JPA seja otimizado de acordo com a necessidade, mas infelizmente não tenho a experiência de multi tenancy que você. Vou ficar atento a isso quando eu cair nesse cenário. [=[/quote]
Oi Herbert, é: quando a gente tá falando de JPA, tem de levar em consideração sempre que não usar um ORM quer dizer um impacto MONSTRO na sua produtividade.
É aquela balança, saca? Você acaba tendo de fazer algumas perguntas do tipo: “tenho tempo pra entregar esta funcionalidade usando JDBC nativo?”, “JPA vai permitir a este sistema escalar de verdade e ainda me possibilitar implementar uma estratégia multi tenant eficiente?”
É questão de por as coisas na balança sempre.
Eu acredito que o melhor é cada cliente com o seu WAR/banco próprios.
Imaginando que existem clientes que demandam mais recursos que os outros, você pode facilmente migrar um cliente “parrudo” para um server melhor e não vai atrapalhar os outros.
Se for tudo em um mesmo banco, isso fica quase impossível de fazer.
Este é apenas um dos problemas que existem quando juntamos todos os clientes em um unico banco.
[quote=kicolobo]Oi Jonas,
este é um dos problemas mais difíceis da computação atualmente: trata-se do problema da multi tenância (multi-tenant).
[/quote]
Mutil-Tenant = Multi-Inquilino (tenant = inquilino)
não existe “tenância”
[quote=sergiotaborda][quote=kicolobo]Oi Jonas,
este é um dos problemas mais difíceis da computação atualmente: trata-se do problema da multi tenância (multi-tenant).
[/quote]
Mutil-Tenant = Multi-Inquilino (tenant = inquilino)
não existe “tenância” [/quote]
Esse Henrique, vou te falar viu… Vive aprontando das suas!
Valeu pelo toque!
[quote=jonas.cant]Numa situação hipotética, quero criar um sistema web de gestão hoteleira que será vendido para vários hotéis diferentes. Estou com dúvida em relação ao acesso ao banco de dados. Como ficaria essa situação? Cada hotel com seu banco de dados? O mesmo banco de dados para todos hotéis? Se cada hotel deverá ter seu próprio banco de dados, como fazer isso utilizando o hibernate sendo que o arquivo de configuração ‘hibernate.cfg.xml’ é estático e atualmente estou passando um nome de banco de dados específico?
Quem puder me ajudar, fico agradecido.[/quote]
O pessoal já lhe deu a resposta de multi-inquilino e o suporte do Hibernate, mas vc não especificou quantos servidores estamos falando.
Quando vc diz “Sistema web para Multiplos Clientes” vc quer dizer que faz um software e vende para vários clientes, ou vc quer dizer que faz um software , instala uma só vez num servidor seu e os clientes pagam para ter acesso ?
O cenário de multi-inquilino só aparece na segunda opção. Na primeira opção, vc edita o arquivo de configuração do war em cada deploy. Ou, o que seria melhor, vc configura o arquivo para usar JNDI e configura o servidor de cada cliente com o banco de dados certo via JNDI. Assim, não tem que editar o seu war e o cliente pode mudar de banco quanto quiser sem ter que mexer com o war.
O pessoal comentou bastante, e tem muita coisa que eu não entendi e talvez por hora eu não conseguiria implementar no sistema. Ainda sou um mero principiante em Java.
Só para esclarecimento, a minha situação hipotética é um TCC que estou desenvolvendo, não pretendo vender o sistema. Só quero desenvolver o TCC de uma forma que possa servir numa situação real.
Vamos ver se eu entendi:
Na primeira opção, para cada cliente que fosse comprar meu sistema eu teria que mudar as configurações de acesso ao banco e gerar um novo arquivo WAR que seria colocado no servidor que será mantido pelo próprio cliente.
Na segunda opção, o servidor seria mantido por minha “empresa” e todos clientes acessariam o sistema naquele servidor.
É isso?