Vários bancos com JPA

29/12/2013

0

Olá pessoal, estou usando em um mesmo servidor de aplicações várias bases de dados, ou seja ao logar vejo qual base o usuário em questão pertence e conecto no mesmo.
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

Fernando Silva

Responder

Post mais votado

29/12/2013

Fala Fernando blz?? boas festas =]

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

Carlos Proença
Responder

Mais Posts

30/12/2013

Fernando Silva

Olá Carlos, boas festas pra você e muita paz.

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.
Responder

07/01/2014

Fernando Silva

Pessoal até o momento o link acima; "http://joaosavio.wordpress.com/2012/05/08/como-usar-varios-bancos-de-dados-com-jpa-hibernate/"

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());
        }
    }
    
    
}

Responder

22/02/2018

Fernando Junior

Boa tarde, Fernando!

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!
Responder

22/02/2018

Fernando Silva

Opa, vou postar a classe que uso atualmente, e esta funcionando.
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());
        }
    }    
}

Responder

01/03/2018

Fernando Junior

Fernando, vou testar aqui e ver o desempenho!
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!
Responder

Assista grátis a nossa aula inaugural

Assitir aula

Saiba por que programar é uma questão de
sobrevivência e como aprender sem riscos

Assistir agora

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar