简体   繁体   中英

Managing Multiple Database Connections

I've been struggling with this problem for days,

Here is the scenario: I have several databases, one for each of my customers, all of them with the same structure(same tables and columns), so my application needs to decide at runtime with which one it needs to connect. I'm using JPA2, EclipseLink and EJB3.

My first attempt was to implement a custom EntityManager with all the logic to performs the operations on the right database, then I configured this EntityManager as an Stateless EBJ in order to make it possible to inject it with the @EBJ annotation (as described at this link: http://www.hostettler.net/blog/2012/11/20/multi-tenancy/ ). I coundn't make it work because it was throwing an exception when trying to inject the EntityManager.

So I decided to try something else, I've created EntityManagerFactory and I passed the JTA_DATASOURCE to it(after decide at runtime which one to use), so it could connect to the right database.

Here is the code:

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class TestEntDAO {

    private EntityManager em;
    private EntityManagerFactory emf;

    @PostConstruct
    public void init() {
        em = getEntityManager();
    }

    public EntityManager getEntityManager() {
        Map props = new HashMap();
        props.put(PersistenceUnitProperties.TRANSACTION_TYPE, "JTA");
        props.put(PersistenceUnitProperties.JTA_DATASOURCE, dataSourceName());
        emf = Persistence.createEntityManagerFactory("testePU", props);
        em = emf.createEntityManager();
        return em;
    }

    public String dataSourceName(){
        if(someCondition){
            return "db1";
        }else{
            return "db2";
        }
    }
}

This worked perfectly, the only problem is that the transaction is not managed by the container, so I had to explicitly mark the transaction's boundaries(call begin() and commit()). I could just use the @PersistenceContext annotation to make it work, but then I wouldn't have the EntityManagerFactory to pass the datasource.

Does anyone know of a way to use the Container-Managed Transactions(CMT) and still be able to pass the datasource?

Maybe try to define 3 Data sources and 3 Persistence units.

<persistence-unit name="PU1">
  <jta-data-source>jdbc/DS1</jta-data-source>
  ...
</persistence-unit>
<persistence-unit name="PU2">
  <jta-data-source>jdbc/DS2</jta-data-source>
  ...
</persistence-unit>
<persistence-unit name="PU3">
  <jta-data-source>jdbc/DS3</jta-data-source>
  ...
</persistence-unit>

And inject Entity manager from whatever Persistence unit you want.

@PersistenceContext(unitName = "PU2")
EntityManager em;

This should work, although I didn't test it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM