My problem is actually simple but I really do not find a good solution to it.
I've currently to manage several DB in my application:
one UNIQUE admin DB (with a static name);
one client DB, with a name depending on the client.
I'm using JPA and I would like to create dynamically EntityManagers for client DB. But when I create this programmatically, I get this error:
javax.persistence.TransactionRequiredException: joinTransaction has been called on a resource-local EntityManager which is unable to register for a JTA transaction.
Here is the code:
#Stateful
public class ServiceImpl implements Service{
private EntityManagerFactory emf;
private EntityManager em;
#PostConstruct // automatically called when EJB constructed and session starts
public void init() {
emf = Persistence.createEntityManagerFactory("punit");
em = emf.createEntityManager();
}
...
And
#Stateful(mappedName = "CustomerService")
public class CustomerServiceImpl extends ServiceImpl implements CustomerService {
#Override
public void create(Customer cust) {
getEm().joinTransaction();
getEm().persist(cust);
}
More generally, I'v got problems with JPA. I just would like to connect to two databases, do some CRUD operations on them. But I really don't know how to manage transactions (my first approach was to let the container manage it...).
If someone could help me, could be great!
NB: I'm using a Glassfish Java EE server and PGSql DBs.
In jpa, you can declare several prsistenceunits in the persistence.xml file.
At the point of injection, you can do something like this:
#PersistenceContext(unitName = "unitName0", properties={#PersistenceProperty(...)}
EntityManager emClient;
#PersistenceContext(unitName = "unitName1", properties={#PersistenceProperty(...)}
EntityManager emAdmin;
This way, you dont have to create the entity managers manually, hence you get the container transaction management.
NOT TESTED:
If you have dynamic database names, you would inject EntityManagerFactory
#PersistenceContext(unitName ="name")
EntityManagerFactory emf;
//at the point you want the EntityManager
Map<String, String> props; //put the connection property for the EM here
EntityManager em = emf.createEntityManager(props);
Based on the fact that in a J2EE environment we use the concept of DataSources, and ConnectionPooling, it would be nearly impossible to implement this kind of dynamic datasources, without resorting to manual creation of entitymanagerfactory.
This is my reasoning:
The server manages the connection pooling, and the jpa provider (such as eclipselink) uses jndi to determine the connection to the database. This implies that if you were to change the database name, then it must also have a connection pooling resources, and an associated jdbc resource. This will ofcourse negate what you want to do.
Basic solution: Create EntityManagerFactory manually and manually manage transactions.
Specify in the persistence xml that the unit is non-jta for this to work.
Then you can programmatically supply connection data based on user-session:
Something of this sort:
//this must be session specific.
class PersistenceSession{
static Map<String, String> clientSessionProps;
//When new session starts and a new client has logged in.
static void setClientConnectionProperties(Client client){
.....
}
static Map<String, String> getClientSessionProps(){
return clientSessionProps;
}
}
At the ejb level.
#Stateless
public class TestEntityFacade extends AbstractFacade<TestEntity> {
private EntityManagerFactory emf;
#PostConstruct
void init(){
emf = Persistence.createEntityManagerFactory("name");
}
#Override
protected EntityManager getEntityManager() {
return emf.createEntityManager(PersistenceSession.getClientSessionProps());
}
public TestEntityFacade() {
super(TestEntity.class);
}
void add(Entity e){
EntityManager em = getEntityManager();
em.getTransaction().begin();
.....
em.getTransaction().commit();
}
}
Actually very neat way how to do this is with CDI Producers, you can define a bean which will produce for your any number of custom Entity Managers, see the example.
#SessionScoped
public class EntityManagerProducer {
#Produces
#AdminDB
#PersistenceContext(unitName = "adminDB")
public EntityManaged adminDB;
#Produces
#UserDB
#PersistenceContext(unitName = "userDB")
public EntityManaged userDB;
}
This means that these two EntityManagers get created within every user session and than you can inject them to any bean with
#Inject
#UserDB
private EntityManager em; //if you want to use UserDB now
#UserDB and #AdminDB are your own defined Qualifiers. This leads to much more easier and readable code.
Related
When should I close connection with database ?
I create connection one time when application starting, and then I use entity manager in this way:
public void createItem(TYPE item){
em.getTransaction().begin();
em.persist(item);
em.getTransaction().commit();
}
public class Connection { //creating connection (one time)
private static final String PERSISTENCE_UNIT_NAME = "ejb";
private static EntityManagerFactory factory;
private static EntityManager em;
static{
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
em = factory.createEntityManager();
}
public static EntityManager getEntityManager() {
return em;
}
}
I think it does not make sense to close connection evey each operation (like create) and create new connecion when I want to save item again.
You should not make entitymanager static, it should be an object that is removed after you do your transactions. This also mean that you should close it after your operation is finished. EntitymanagerFactory can stay static, you only need 1 for each program run. The reason as to why you should close it is that you are wasting resources on your device.
Longer/ better explanation on EMF https://stackoverflow.com/a/4544053/6270761
As far as i know the EntityManager is just abstraction to handle work-unit in ongoing transaction, if you created it using EntityManagerFactory which it is in current implementation you have to close it no matter what framework or template you are using.
If you obtained it using dependency injection (eg using EJB and #PersistenceContext annotation) you should not close it by hand i.e. it will close by embed dependency which you injected, the idea is to always close java.sql.Connection to prevent resource leak.
More over the application has finished using the entity manager factory, and/or at application shutdown, the application should close the entity manager factory. Once an EntityManagerFactory has been closed, all its entity managers are considered to be in the closed state as well.
I am seeing two classes:
/**
* This class uses CDI to alias Java EE resources, such as the persistence context, to CDI beans
*
*/
public class Resources {
#Produces
#PersistenceContext
private EntityManager em;
#Produces
public Logger produceLog(InjectionPoint injectionPoint) {
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
#Produces
#RequestScoped
public FacesContext produceFacesContext() {
return FacesContext.getCurrentInstance();
}
}
and
// The #Stateless annotation eliminates the need for manual transaction demarcation
#Stateless
public class MemberRegistration {
#Inject
private Logger log;
#Inject
private EntityManager em;
#Inject
private Event<Member> memberEventSrc;
public void register(Member member) throws Exception {
log.info("Registering " + member.getName());
em.persist(member);
memberEventSrc.fire(member);
}
}
I have 2 questions on this:
1) MemberRegistration can inject "log" and "em" directly, is that because the Resources already define them by using #Produces annotation? Without the Resources class, would the MemberRegistration class still work? I am trying to understand whether or how the two classes are related, and how the CDI works.
2) In MemberRegistration's register method, there is only a "em.persist()" method used. A complete flow of using EntityManager looks like the following. In the example application, I didn't see methods "commit()" and "close()" are used. So how the transaction is committed and closed?
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
entityManager.persist( SomeObject );
entityManager.getTransaction().commit();
entityManager.close();
Answering your questions:
1) MemberRegistration can inject "log" and "em" directly, is that because the Resources already define them by using #Produces annotation?
Yes. #Inject will work only for types that are known to CDI (are discovered via class-path scanning or declared manually via #Produces). So without your Resources class, which defines EntityManager and Logger as a CDI managed beans, injection via #Inject would not work.
BTW. For details you can read cdi-spec-1.2 - PDF version is 170 pages long, not that big, but also not so short.
2) So how the transaction is committed and closed?
... you even have a valid comment in your code: the #Stateless annotation eliminates the need for manual transaction demarcation. For details read something about CMT transactions in EJB.
Honestly, I agree with #JBNizet. It is disappointing to see you asking such questions (especially the first one) which can be answered immediately by yourself with just a quick test.
First of all I am new to JPA and Jax-rs, i am trying to develop a rest service. So i have created a resource class and annotated it.
#Path("/companies")
public class CompanyResource {
private EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("test");
#GET
#Produces({MediaType.APPLICATION_JSON})
public List<Company> getCompanies() {
EntityManager entityManager = entityManagerFactory.createEntityManager();
return new ArrayList<>();
}
#GET
#Path("{companyId}")
#Produces({MediaType.APPLICATION_JSON})
public Company getCompany(#PathParam("companyId") int id) {
return new Company();
}
}
From what i have understood about jax-rs for every client request instance of CompanyResource will be created, that means every time new EntityManagerFactory will be created, which i guess is not a good idea, as i just need it to create entity managers, which could be done with only one instance of it. So what is a proper way to achieve this? Or is it ok to create new instance of this factory for every request?
P.S. i have seen some examples where they use #Stateless annotation and inject Entity Manager, but i guess they use EJB there(i might be wrong) and i don't want to deep into EJB right now.
I think you should inject the entitymanager itself (not the factory), and let the container take care of instantiation and scopes. What we usually do is something like
#Stateless
#Path("services")
public class MyServices {
#PersistenceContext
private EntityManager em;
// ...
apart from the #Stateless (which imho you should use, there's no need to get deep into EJB for this), it's actually quite simple.
Let's suppose I have a simple lib named db-utils, which has a CrudService CDI bean (requestScoped) that's used by my web applications to perform CRUD operations.
I also have an EJB project named grad-db, which has the entities mapped from database. Grad-db also has the producer used to set the entityManager in db-utils' CrudService.
I already tried it and apparently it works fine. My question is: is that a bad practice? Is there any consequence of producing a CDI bean inside a stateless session bean and passing the EJB stateless bean as a parameter to the CrudService?
My code:
EJB Bean (grad-db):
#Stateless
public class CrudServiceCae extends AbstractCrud implements Serializable {
private static final long serialVersionUID = 1L;
#PersistenceContext(unitName = "cae-pu")
EntityManager em;
#Override
public EntityManager getEntityManager() {
return em;
}
#Produces
#Database(Schema.CAE)
public CrudService createCrudServiceCou() {
return new CrudService(this);
}
}
CrudService (db-utils):
#Named("crudService")
public class CrudService implements Serializable {
private static final long serialVersionUID = -2607003150201349553L;
private AbstractCrud crud;
public CrudService(AbstractCrud abstractCrud) {
this.crud = abstractCrud;
}
...
}
Edit:
Actually it worked only for queries. When I tried to insert data I got javax.persistence.TransactionRequiredException. Apparently I'm going to have to use inheritance instead of CDI in this case.
The EJBs are responsable for business processes/logic (i.e: methods), and are able to orchestrating others CDI controllers, is not so common let the EJB create objects, for that you would prefer a CDI POJO Producer.
In your case is leaner to use a CDI object and produce the object that you need from there, looks like a DAO and could be used (i mean, injected) into the EJB.
Think of EJBs on terms of a Boundary Pattern, using specialized controllers.
Notes:
#Stateless is not required to implements Serializable, these are pooled, and its lifecycle does not allow serialization.
In general you dont want to use a getter to the entity manager of an EJB, you should prefer write a method and use the em internally.
The persistence context is easier to manipulate if uses JTA
Your #Stateless should begins the transactions and let them propagated along the controllers
The em with package visibility is a good idea, lets you mock your facade / boundary easily
Considering there is no #PersistenceContext available to inject the EntityManager, plus you need to manually manage Transactions, what is the best way to design such an application?
For the EntityManagerFactory/EntityManager, as far as I can see, you must have each DAO accepting an EntityManager in the costructor e.g.
public class DAOImpl implements DAO
{
private EntityManager em;
DAOImpl(EntityManager em){
this.em = em;
}
//all CRUD operations follow
}
The first question that rises is when do you call EntityManager#close()?
Point A: The way I see it, you are better off doing this in a Filter at the end of the request cycle, which implies that you associate the EntityManager with the current thread (using ThreadLocal?)
Second question is, how and when do you inject the EntityManager?
Considering there is a ServletContextListener where we create and close the EntityManagerFactory, we could have a static method as follows
public static EntityManager createEntityManager(){
return entityManagerFactory.createEntityManager(PERSISTENT_NAME);
}
but since we want to encapsulate creating the DAO, we could use a factory e.g.
public class DAOFactory
{
public static DAO dao(){
//return a new DAO
}
}
As per Point A we should use a ThreadLocal to create the DAO using the EntityManager for the current Thread.
For managing Transactions.
The best way I can think of (which mimics the JPA spec) is to create your own Transaction annotation and use reflection to inject the begin/commit/rollback operations.
You should then return a Proxy from the DAOFactory which handles the transactions
I wouldn't do all that. Why try to recreate the whole JPA spec yourself? You just need to be able to use JPA without a container.
Spring can help you with this. Try it.