I have a database with multiples schemas so I have a persistence.xml file with multiples <persistence-unit /> (named 01, 02, ...).
Problematic :
I want to create an EntityManager dynamically function of some user criteria.
I have tested 2 cases.
First case : basically, I tested this code (inside stateless EJB) :
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 received exception :
Caused by: 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 help of some Stackoverflow posts), that my EntityManager wasn't "linked" to my transaction context due to the fact it wasn't injected by container.
Second case : thus, I used injection :
#PersistenceContext(unitName="00")
private EntityManager em00;
#PersistenceContext(unitName="01")
private EntityManager em01;
Code in my function :
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, it's work but I have to inject as many EntityManagers that I have persistence-unit.
What will be the cost if I have 50 schemas...?
Is there a way to really manage entities managers dynamically ? (1 EntityManger only)
If I have to create 1 EntityManager per schema even if I don't use it, how can I improve my code to consume the least amount of resources possible ?
Thank you for advices and feedbacks
EDIT :
My configurations 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>
You need to set the "eclipselink.target-server" to the application server you are using when using application managed persistence units (some servers set this automatically then using container managed persistence units). Then the EntityManager will bind with the JTA transaction that is active when it is created. If you create the EntityManager before the start of the JTA transaction then you can use joinTransaction().
If you still have issues, include the server you are using, and the full exception stack trace.
If you have a lot of schemas, you could consider using EclipseLink multi-tenant support, which allows each tenant to have their own schema.
http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_multitenant.htm#BABEGBIJ
Usually you don't have 50 schemas. I would not worry about the cost of injections, as usually EJB container has a pool of already opened connections which are ready to be injected. So the overhead is really small.
AFAIK, JPA does not allow dynamic entity managers.
If you care about resources, I would suggest to avoid using EclipseLink (I had really bad experience with EclipseLink + EJBs)
To optimize things a bit I would try to use factory pattern here. Create a Bean which will serve you EntityManagers. Instead of injecting several PersistenceContext you will have one injection with a method like:
EntityManager getEntityManager(String schemaId) {...}
Another option is to move all injections to an AbstractBean. All other beans inherit from the AbstractBean.
Related
I am getting the following error when I am using Jboss 4.2.3 GA and configured my ms-sql.ds file. I created an Entity Bean EJB3 and I am trying to access that Entity bean from EJB 2.1 Session Bean. First of all, I wanted to check if it is possible. Because when I use EntityManager or EntityManagerFactory,
my EntityManager is comming as null. Also instead if I use EntityManagerFactory, it gives
an error saying:
javax.persistence.PersistenceException: No Persistence provider for
EntityManager named EjbComponentPU
Below is my class
public class TestBean implements SessionBean {
//pass persistence unit to entityManager.
#PersistenceContext(unitName="EjbComponentPU")
private EntityManager entitymanager;
My Project folder structure is:
src - has the all the packages.
Inside that I have META-INF folder which has the persistence.xml file
Thanks for any help.
this is my persistence.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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_1_0.xsd">
<persistence-unit name="EjbComponentPU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/testDS</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
I would like to get my DataSource properties, like user name or url.
This is my persistence.xml:
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="defaulttransaction-type="JTA">
<jta-data-source>MyDataSource</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
</persistence>
Inside GlassFish 4.1, I have the required JDBC Resource and JDBC ConnectionPool, respectively MyDataSource and MyDataSourceCP.
If this is useful, MyDataSource is a javax.sql.ConnectionPoolDataSource and MyDataSourceCP is a oracle.jdbc.pool.OracleConnectionPoolDataSource.
MyDataSourceCP is configured with some parameters like URL, user name and password.
I would like to extract those properties from Java.
So far, I have tried the following:
How to get jpa datasource properties from Entity Manager
How to retrieve the datasource used by a persistence unit programmatically
JPA - Is there a way/method to retrieve Persistence Unit information
But with no results.
As #Stoffelchen (in (1)), I would like something like
someObject.someMethod( ).getProperties( )
// or
someObject.someMethod( ).getProperties( "username" )
// or
someObject.someMethod( ).getUserName( )
Is there a way to achieve this?
I am using Hibernate 4.3.
Thanks in advance
I need two or more than two connections in my web application using jpa
To use different data sources, add multiple persistence units (say, source-1 and source-2 in persistence.xml and create multiple EntityManagerFactoryes by name):
EntityManagerFactory emf1 = Persistence.createEntityManagerFactory("source-1");
EntityManagerFactory emf2 = Persistence.createEntityManagerFactory("source-2");
or, if you're working on Spring or Java EE application server, inject them by name also:
#PersistenceUnit(name = "source-1")
EntityManagerFactory emf1;
#PersistenceContext(unitName = "source-2") // as an option
EntityManager em2;
persistence.xml will thus look like the following:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="source-1" transaction-type="RESOURCE_LOCAL">
<properties>
<!-- source-1 properties here -->
</properties>
</persistence-unit>
<persistence-unit name="source-2" transaction-type="RESOURCE_LOCAL">
<properties>
<!-- source-2 properties here -->
</properties>
</persistence-unit>
</persistence>
Example of how to configure persistence unit, create EntityManager to manage entities and execute queries can be found here.
For single datasource jpa will use multiple connections internally.So you don't need to do anything.
I have a JAX-RS restful service which needs to access a MySQL database. I am trying to do this using CDI and a entity manager. However, when I publish the app, it appears that the incorrect persistence unit is being used (it's trying to connect on port 1527 instead of 3306).
The exception that is caught by the try/catch is:
javax.servlet.ServletException:
javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504):
org.eclipse.persistence.exceptions.DatabaseException
Internal Exception:
java.sql.SQLException:
Error in allocating a connection. Cause: Connection could not be allocated because:
java.net.ConnectException : Error connecting to server localhost on port 1527 with message Connection refused: connect.
Error Code: 0
Here is the restful service:
#Path("/databases")
#Stateless
public class DatabaseResource {
#PersistenceUnit(unitName = "beta.example.services")
EntityManagerFactory entityManagerFactory;
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response list() {
try {
EntityManager entityManager = entityManagerFactory.createEntityManager();
Connection connection = entityManager.unwrap(java.sql.Connection.class);
...
return Response.ok().build();
} catch (SchemaCrawlerException e) {
return Response.status(500).entity(e.getMessage()).build();
}
}
}
The persistence unit (located in src/META-INF):
<?xml version="1.0" encoding="UTF-8"?>
<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="beta.example.services">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/" />
<property name="javax.persistence.jdbc.user" value="test" />
<property name="javax.persistence.jdbc.password" value="test" />
</properties>
</persistence-unit>
</persistence>
Any help would be appreciated
Ok, a persistence unit can be configured in two modes : RESOURCE_LOCAL and JTA.
Ex:
<persistence-unit name="beta.example.services" transaction-type="JTA">
VS
<persistence-unit name="beta.example.services" transaction-type="RESOURCE_LOCAL">
JTA is the default value. Properties like "javax.persistence.jdbc.*" will only be read when using "RESOURCE_LOCAL". When using JTA, the transaction manager of glassfish will be used. That means in this case you must specify JNDI name like this :
<jta-data-source>youJNDIName</jta-data-source>
What I think might be happening is that you use the default "JTA" transaction-type, but since you dont specify any jta-datasource, it might try to use the glassfish default one (wich point to derby).
Persistence unit as RESOURCE_LOCAL or JTA?
http://openejb.apache.org/jpa-concepts.html
Looking at how you use the entity manager, setting transaction-type to RESOURCE_LOCAL seems to be the solution for you.
We created some libraries that all our projects will use, this libraries will provide the basic functionality of all our systems (login, some manage, etc). But the application itself could use another database.
What we did was to create the Persistence.xml with two persist units. And package all the core library entities in a jar called "LN-model.jar" and all of the entities of out test app in "App-model.jar". But for some reason we still obtain the following message.
Could not resolve a persistence unit corresponding to the persistence-context-ref-name [x.x.x.x.listener.InicializadorListener/em] in the scope of the module called [gfdeploy#/Users/zkropotkine/WORK/SeguridadCore/dist/gfdeploy/SeguridadCore-war_war]. Please verify your application.
Here's our Persistence.xml
<persistence version="1.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_1_0.xsd">
<persistence-unit name="x" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/x</jta-data-source>
<jar-file>App-model.jar</jar-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
</properties>
</persistence-unit>
<persistence-unit name="y" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/y</jta-data-source>
<jar-file>LN-model.jar</jar-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
By the way we put the Persistence.xml in a jar, that we add to our Enterprise Project (EAR).
The problem is that the JPA does not know which is the persistence unit to use. when you have only one persistence unit this problem does not occur. To fix do the following:
You need to specify a persistence unit : #PersistenceContext(unitName="...") in the Ejb that do not have
You can add the annotations:
#PersistenceUnit(name = "x")
EntityManagerFactory entityManagerFactory;
#PersistenceContext(unitName = "y")
EntityManager entityManager;
Or you can create it manually:
EntityManagerFactory emfA = Persistence.createEntityManagerFactory("x", properties);
EntityManagerFactory emfB = Persistence.createEntityManagerFactory("y", properties);
For more details, please see the following link: https://docs.oracle.com/html/E25034_01/usingmultipledbs.htm
is very useful, to me helped me!