Handle EntityManager dynamically with multiple repeat units

I have a database with multiple schemas, so I have a persistence.xml file with short values <persistence-unit /> (named 01, 02, ...).

Problem: I want to create a dynamic EntityManager function for some custom criteria.

I tested 2 cases.

The first case: basically, I tested this code (inside a stateless EAN server):

 String criteria = "01"; EntityManagerFactory emf = Persistence.createEntityManagerFactory(criteria); EntityManager em = emf.createEntityManager(); Joueur joueur = new Joueur(); // Joueur is an Entity joueur.setPseudo("olivier"); em.persist(joueur); 

but I got an exception:

Raised: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException Internal exception: org.postgresql.util.PSQLException: ERREUR: la transaction est annulée les commandes sont ignorées jusqu'à la fin du bloc de la transaction

I thought (with some Stackoverflow posts) that my EntityManager was not associated with my transaction context due to the fact that it was not nested by the container.

Second case: thus, I used the injection:

 @PersistenceContext(unitName="00") private EntityManager em00; @PersistenceContext(unitName="01") private EntityManager em01; 

The code in my function is:

 String criteria = "01"; EntityManager em = getEm(criteria); ... 

and getEm () method:

 private EntityManager getEm(String criteria){ if (criteria == "00") return em00; else if (criteria == "01") return em01; return null; } 

No problem, this works, but I have to introduce so many EntityManager that I have a persistence unit.

  • What will be the cost if I have 50 schemes ...?
  • Is there a way to manage entity managers dynamically? (Only 1 EntityManger)
  • If I need to create 1 EntityManager for each scheme, even if I do not use it, how can I improve my code to consume the least amount of resources?

Thanks for the tips and feedback.

EDIT:

My configuration files:

Persistence.xml:

 <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="00" transaction-type="JTA"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <jta-data-source>jdbc/sim/00</jta-data-source> <mapping-file>orm_00_beta.xml</mapping-file> <class>com.sim.entities.Joueur</class> <properties> <property name="eclipselink.ddl-generation" value="create-tables" /> </properties> </persistence-unit> <persistence-unit name="01" transaction-type="JTA"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <jta-data-source>jdbc/sim/01</jta-data-source> <mapping-file>orm_01_beta2.xml</mapping-file> <class>com.sim.entities.Joueur</class> <properties> <property name="eclipselink.ddl-generation" value="create-tables" /> </properties> </persistence-unit> </persistence> 

orm_00_beta.xml:

 <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd" version="2.0"> <persistence-unit-metadata> <persistence-unit-defaults> <schema>beta</schema> </persistence-unit-defaults> </persistence-unit-metadata> 

orm_01_beta2.xml:

 <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd" version="2.0"> <persistence-unit-metadata> <persistence-unit-defaults> <schema>beta2</schema> </persistence-unit-defaults> </persistence-unit-metadata> 

+4
source share
2 answers

You need to install "eclipselink.target-server" on the application server that you use when using application-managed storage units (some servers install this automatically and then use container-managed containers). Then, the EntityManager will contact the JTA transaction, which is active when it is created. If you create an EntityManager before starting a JTA transaction, you can use joinTransaction ().

If you still have problems, turn on the server you are using and the full trace of the exception stack.

If you have many schemes, you can consider using EclipseLink's multi-user support, which allows each tenant to have their own scheme.

http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_multitenant.htm#BABEGBIJ

+2
source

Usually you do not have 50 circuits. I would not worry about the cost of injections, as an EJB container usually has a pool of already open connections that are ready for injection. Thus, the overhead is really small.

AFAIK, JPA does not allow dynamic entity managers.

If you need resources, I would advise against using EclipseLink (I had really bad experience with EclipseLink + EJB)

To optimize things a bit, I would try using the factory pattern here. Create a Bean that will serve you EntityManagers. Instead of injecting multiple PersistenceContext, you will have one injection using a method, for example:

 EntityManager getEntityManager(String schemaId) {...} 

Another option is to move all injections to AbstractBean. All other beans inherit from AbstractBean.

+1
source

Source: https://habr.com/ru/post/1447484/


All Articles