Vários bancos com JPA
29/12/2013
0
Porém, toda vez que o ultimo usuário loga, o JPA muda o banco de todas as sessões.
Pela análise que fiz, reparei que tenho uma classe utilitária do JPA que esta fazendo isto, agora a duvida é como fazer a alteração nesta classe, uma vez que ela foi construída assim devido á este método ser muito pesado "Persistence.createEntityManagerFactory", gostaria que me ajudassem a fazer esta mudança, ou seja cada usuário da sessão da aplicação acessem seu respectivo banco.
Pensei em criar uma instancia desta classe no "Bean" de login e manter o objeto instanciado para cada usuário logado o que acham?
Desta forma retiraria o padrão "singletow" desta classe e deixaria como classe normal.
Vejam a classe utilitária em questão.
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package jpa; import java.util.Properties; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import jdbc.FactoryConnection; import util.Criptografia; import util.VarPub; /** * * @author Fernando */ public class JPAUtil { private static JPAUtil em; private EntityManagerFactory factory; private Properties prop; private static String nomeBanco = ""; private static String userBanco = ""; private static String senhaBanco = ""; //jdbc:postgresql://127.0.0.1:5432/commit // private JPAUtil(){ prop = new Properties(); prop.put("javax.persistence.jdbc.url", this.nomeBanco); prop.put("javax.persistence.jdbc.password", this.senhaBanco); prop.put("javax.persistence.jdbc.user", this.userBanco); factory = Persistence.createEntityManagerFactory(VarPub.bancoCommit, prop); } // public static JPAUtil getInstace(){ if (em == null){ em = new JPAUtil(); } return em; } // public boolean alteraBanco(String _nomeBanco, String _enderecoBanco, String _userBanco, String _senhaBanco){ //Metodo critico pois caso conectar no banco errado pode causar sérios problemas try { if(!(_nomeBanco.isEmpty()&&_enderecoBanco.isEmpty()&&_userBanco.isEmpty()&&_senhaBanco.isEmpty())){ JPAUtil.em = null; FactoryConnection.setCon(null); this.factory = null; // 127.0.0.1 (local) // pgsql.commitsistemas.com.br (Remoto) JPAUtil.nomeBanco = "jdbc:postgresql://"+_enderecoBanco.trim()+"/"+_nomeBanco.trim(); JPAUtil.userBanco = _userBanco.trim(); //Primeiro acesso ao banco de dados do commitsistemas if(_nomeBanco.trim().equals(VarPub.bancoCommit)){ JPAUtil.senhaBanco = VarPub.senhaBancoCommit; }else{ JPAUtil.senhaBanco = Criptografia.decriptar(_senhaBanco.trim()); } JPAUtil.em = new JPAUtil(); return true; } } catch(Exception e) { return false; } return false; } // public EntityManager createEntityManager(){ EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); return em; } // public static String getNomeBanco() { return nomeBanco; } public static String getUserBanco() { return userBanco; } public static String getSenhaBanco() { return senhaBanco; } // }
Desde já agradeço a atenção de todos.
Fernando Silva
Post mais votado
29/12/2013
Cara complicado.... isso ai.... vc tem que ajustar para que sua app seja thread safe e tambem n tenha problema de performance .... pois ficar criando o factory para toda transação eh complicado.... da uma boa olhada nisso ein....
olha.. tem varias maneiras de conseguir isso.. dependendo do que vc esta usando.... olha ai oq eu achei na net rapidinho sobre isso....
.http://joaosavio.wordpress.com/2012/05/08/como-usar-varios-bancos-de-dados-com-jpa-hibernate/
http://blog.jesjobom.com/2012/06/configuracao-de-multiplas-unidades-de-persistencia-com-jpa/
ve se vc consegue usar o @PersistenceContext pra isso...
look http://www.guj.com.br/java/259862-jpa-com-2-bancos-de-dados
eu nunca fiz um projeto assim tb rs... fiquei curioso da melhor forma de se fazer isso....
posta ai os resultados pra galera... e boa sorte.. e estamos ai
Carlos Proença
Mais Posts
30/12/2013
Fernando Silva
Já tinha olhado essa abordagem que você indicou.
"http://joaosavio.wordpress.com/2012/05/08/como-usar-varios-bancos-de-dados-com-jpa-hibernate/"
Mas teria muita alteração no meu fonte, porém pelo que vejo esta é a melhor opção vou implementar e posto aqui se funcionar.
Só lembrando que não uso dois arquivos Persistence.xml, apenas um e altero as propriedades, porem creio que, a analogia é a mesma do post indicado.
De qualquer maneira obrigado.
07/01/2014
Fernando Silva
funcionou perfeito, porem estou com duvida eu preciso usar mesmo esta "ThreadLocal"?
E sobre o "synchronized", será que entendi bem, ele faz com seja executado uma thread por vez do método que o implementa.
abaixo, minha classe com as alterações baseadas na classe no exemplo do link.
Favor me ajudem ai com as considerações, pelos testes iniciais abri o sistema em dois navegadores e funcionou legal, buscando os dados cada um em seu respectivo banco de dados.
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package jpa; import entidades.admsis.AdmsisContratos1; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import util.Criptografia; import util.EncryptorException; import util.MetPub; import util.VarPub; /** * * @author Fernando */ public class JPAUtil { private static Map<String, EntityManagerFactory> factories = new HashMap<String, EntityManagerFactory>(); // public static synchronized EntityManager createEntityManager(AdmsisContratos1 _contrato) throws Exception{ try { EntityManager em = getEntityManagerFactory(_contrato).createEntityManager(); em.getTransaction().begin(); return em; } catch (Exception e) { System.err.println(""+e.getLocalizedMessage()); } return null; } // private static synchronized EntityManagerFactory getEntityManagerFactory(AdmsisContratos1 _contrato) throws EncryptorException{ // if (factories.containsKey(_contrato.getNomebanco1().trim())) { System.out.println("Recuperou conexão: "+_contrato.getNomebanco1().trim()); return factories.get(_contrato.getNomebanco1().trim()); } //Não existe conexão aberta para esta conta EntityManagerFactory emf = null; Properties prop = new Properties(); String senhaBanco = ""; //Primeiro acesso ao banco de dados do commitsistemas senhaBanco = Criptografia.decriptar(_contrato.getSenhabanco1().trim()); prop.put("javax.persistence.jdbc.url", MetPub.getInstace().getUrlConexaoBanco(_contrato)); prop.put("javax.persistence.jdbc.password", senhaBanco); prop.put("javax.persistence.jdbc.user", _contrato.getUserbanco1()); try { emf = Persistence.createEntityManagerFactory(VarPub.commitPU, prop); } catch (Exception e) { // handle exception } System.out.println("Nova conexão: "+_contrato.getNomebanco1().trim()); factories.put(_contrato.getNomebanco1().trim(), emf); return emf; } // public static synchronized void closeEntityManagerFactory(AdmsisContratos1 _contrato)throws Exception{ if(factories.containsKey(_contrato.getNomebanco1().trim())) { if(factories.get(_contrato.getNomebanco1().trim()).isOpen()){ factories.get(_contrato.getNomebanco1().trim()).close(); } factories.remove(_contrato.getNomebanco1().trim()); } } }
22/02/2018
Fernando Junior
Cara, me desculpa incomodar, mas precisava de uma força!
Estou começando um projeto parecido com o seu. Vou identificar o usuário e cada um deles vai acessar sua base de dados.
A questão é que o número de usuários poderá ser muito grande e estou preocupado com a performance do sistema.
Como você fez pra implementar essa solução?!
Pensei no C3PO para fazer o pool de conexões, mas não sei se ele seria capaz de aguentar o tranco!
22/02/2018
Fernando Silva
Eu tenho no máximo 3 ou 4 bancos no mesmo servidor de aplicação e funciona bem.
public class FactoryConnection { private static Map<String, Connection> listaCon = new HashMap<String, Connection>(); // public static synchronized Connection getConnection(AdmsisContratos1 _contrato) throws Exception{ // if (listaCon.containsKey(_contrato.getNomebanco1().trim())) { if(!listaCon.get(_contrato.getNomebanco1().trim()).isClosed()){ return listaCon.get(_contrato.getNomebanco1().trim()); } listaCon.remove(_contrato.getNomebanco1().trim()); } //Não existe conexão aberta para esta conta Connection con = null; try { Class.forName("org.postgresql.Driver"); con = DriverManager.getConnection(MetPub.getInstace().getUrlConexaoBanco(_contrato), VarPub.userBancoERP, VarPub.senhaBancoERP); } catch (Exception e) { // handle exception if(listaCon.containsKey(_contrato.getNomebanco1().trim())) { listaCon.remove(_contrato.getNomebanco1().trim()); } throw e; } listaCon.put(_contrato.getNomebanco1().trim(), con); return con; } // public static void limpaConexao(){ listaCon = new HashMap<>(); } // public static synchronized void closeConnection(AdmsisContratos1 _contrato)throws Exception{ if(listaCon.containsKey(_contrato.getNomebanco1().trim())) { if(!listaCon.get(_contrato.getNomebanco1().trim()).isClosed()){ listaCon.get(_contrato.getNomebanco1().trim()).close(); } listaCon.remove(_contrato.getNomebanco1().trim()); } } }
01/03/2018
Fernando Junior
A ideia é usar uma quantidade bem maior de bancos...
Mas a partir daqui eu já consigo começar a pensar em alguma outra solução, se for necessário.
Com sua ajuda eu já tenho um caminho. Mto obrigado mesmo!
Clique aqui para fazer login e interagir na Comunidade :)