Ok, I read bunch of articles/examples how to write Entity Manager Factory in singleton.
One of them easiest for me to understand a bit:
http://javanotepad.blogspot.com/2007/05/jpa-entitymanagerfactory-in-web.html
I learned that EntityManagerFactory (EMF) should only be created once preferably in application scope.
And also make sure to close the EMF once it's used (?)
So I wrote EMF helper class for business methods to use:
public class EmProvider {
private static final String DB_PU = "KogaAlphaPU";
public static final boolean DEBUG = true;
private static final EmProvider singleton = new EmProvider();
private EntityManagerFactory emf;
private EmProvider() {}
public static EmProvider getInstance() {
return singleton;
}
public EntityManagerFactory getEntityManagerFactory() {
if(emf == null) {
emf = Persistence.createEntityManagerFactory(DB_PU);
}
if(DEBUG) {
System.out.println("factory created on: " + new Date());
}
return emf;
}
public void closeEmf() {
if(emf.isOpen() || emf != null) {
emf.close();
}
emf = null;
if(DEBUG) {
System.out.println("EMF closed at: " + new Date());
}
}
}//end class
And my method using EmProvider:
public String foo() {
EntityManager em = null;
List<Object[]> out = null;
try {
em = EmProvider.getInstance().getEntityManagerFactory().createEntityManager();
Query query = em.createNativeQuery(JPQL_JOIN); //just some random query
out = query.getResultList();
}
catch(Exception e) {
//handle error....
}
finally {
if(em != null) {
em.close(); //make sure to close EntityManager
}
//should I not close the EMF itself here?????
EmProvider.getInstance().closeEmf();
}
I made sure to close EntityManager (em) within method level as suggested. But when should EntityManagerFactory be closed then? And why EMF has to be singleton so bad??? I read about concurrency issues but as I am not experienced multi-thread-grammer, I can't really be clear on this idea.
EntityManagerFactory instances are
heavyweight objects. Each factory
might maintain a metadata cache,
object state cache, EntityManager
pool, connection pool, and more. If
your application no longer needs an
EntityManagerFactory, you should
close it to free these resources.
When an EntityManagerFactory closes,
all EntityManagers from that factory,
and by extension all entities managed
by those EntityManagers, become
invalid.
It is much better to keep a factory
open for a long period of time than
to repeatedly create and close new
factories. Thus, most applications
will never close the factory, or only
close it when the application is
exiting.
Only applications that require
multiple factories with different
configurations have an obvious reason
to create and close multiple
EntityManagerFactory instances.
Only one EntityManagerFactory is
permitted to be created for each
deployed persistence unit
configuration. Any number of
EntityManager instances may be
created from a given factory.
More than one entity manager factory
instance may be available
simultaneously in the JVM. Methods of the EntityManagerFactory
interface are threadsafe.
Related
My application is crashing with the error below:
org.hibernate.HibernateException: Flush during cascade is dangerous
I am not flushing unless hibernate is doing it on my behalf.
Specs:
webapp on tomcat
hibernate/jpa for persistence (application managed
entity manager)
This is the code of my util class to manage entity manager:
private static EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("returnit");
private static EntityManager entityManager;
public static EntityManager getEntityManager(){
return entityManager;
}
public static EntityManager initEntityManager(){
if (emFactory == null) {
emFactory = Persistence.createEntityManagerFactory( "returnit" );
}
entityManager = emFactory.createEntityManager();
return entityManager;
}
And this is the method that triggers the error:
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response post(#HeaderParam(HttpHeaders.AUTHORIZATION) String authHeader, MasterCrossDock mcd) {
EntityManager em = Utils.initEntityManager();
em.getTransaction().begin();
MasterCrossDockDAO.save(mcd);
em.getTransaction().commit();
em.close();
return Response.ok(mcd.getId()).build();
}
public static void save(MasterCrossDock new_mcd) {
List<Receptacle> receptacles = new_mcd.getReceptacles();
List<Long> ids = new ArrayList<Long>();
for (Receptacle r: receptacles) {
ids.add(r.getId());
}
new_mcd.getReceptacles().clear();
EntityManager em = Utils.getEntityManager();
new_mcd.getCountryDestination())
em.createQuery("UPDATE receptacle r"
+ " SET r.masterCrossDock.id = :mcd_id"
+ " WHERE r.id IN :ids")
.setParameter("ids", ids)
.setParameter("mcd_id", new_mcd.getId())
.executeUpdate();
new_mcd.getEreturns());
}
Why am I getting the error above and how to fix it?
Entity manager is not thread safe. Using EntityManager in container managed transatcions is fine, but here you are managing both the EntityManager and the transaction yourself. Also the entity manager is static so you are effectivly re-using it over the different requests you may get from the controller. Incoming call would execute the update query which would invoke a flush.
I noticed that during your initEntityManager you are swapping the static instance of the entityManager with a new one. What about the old reference that may be in use by another thread ?
Do the following:
Delete entirly your method initEntityManager
Delete private static EntityManager entityManager;
Make you method Utils.getEntityManager(); to aways create a new EntityManager
Alternative solution should be to make Spring or your container if you use container manage your transactions. Make a service, annotate it with #Transaction attribute and make Spring/Container inject the EntutyManager in it, or just use spring-data repositories.
The flush operation is called by the EntityTransaction Hibernate implementation, which might be JdbcResourceLocalTransactionCoordinatorImpl in your case, on commit.
Inside SessionImpl, this is what throws the HibernateException.
private void doFlush() {
checkTransactionNeeded();
checkTransactionSynchStatus();
try {
if ( persistenceContext.getCascadeLevel() > 0 ) {
throw new HibernateException( "Flush during cascade is dangerous" );
}
...
Maybe, and I say maybe, some other thread got a hold on the Session object and is operating on your entities.
I am following Hibernate video lesson, and there were shown this code:
public class Main {
private static EntityManagerFactory entityManagerFactory;
public static void main(String[] args)
{
entityManagerFactory = Persistence.createEntityManagerFactory("org.hibernate.tutorial.jpa");
addEntities("Client1","Bank1");
entityManagerFactory.close();
}
private static void addEntities(String clientName, String BankName)
{
Client client = new Client();
client.setName(clientName);
Bank bank = new Bank();
bank.setName(BankName);
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
entityManager.flush();
entityManager.persist(client);
entityManager.persist(bank);
entityManager.getTransaction().commit();
}
}
And I am concerned about this part of code:
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
entityManager.flush();
We generated new EntityManager. As I understand, it has empty Persistence context, as it was just created, isn't it ?
In that case,why do we call flush() method. What is the purpose ?
EntityManager#flush actually pushes the changes to the database immediately.
In the above code, a transaction has just started entityManager.getTransaction().begin() and there is no change that needs to be pushed to the database so I would say it is not needed there. You may remove it.
Anyways, it is a good practice to let entitymanager take care of when to push the data changes to the database instead of manually taking control over it. There could be use case when different applications or threads are trying to access the same data at same time.
I'm simply unable to inject EntityManagerFactory object from ProfileDBUtil into ProfileManager class where I actually apply the transactions to look for an entry in the database, or update a row and so.
createEntityManager() method throws the exception specified in the end of the entry.
The weird thing is that the same piece of code works for UAT environment while it fails for SIT environment. All config is the same for both of the environments. Class loader order, shared lib references, module class loaders are the same.
Both of the environments have the necessary jars in their file system and seem to be loaded successfully in runtime.
What would be the root cause for this problem?
public class ProfileDBUtil {
private static final String PERSISTENCE_UNIT = "com.profile.userdb";
public boolean loadProfile(String memberID) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
ProfileManager upm = new ProfileManager(emf);
List < Profile > ProfileList = upm.searchProfile(memberID);
}
}
#SuppressWarnings("unchecked")
#JPAManager(targetEntity = com.profile.userdb.model.Profile.class)
public class ProfileManager {
private EntityManagerFactory emf;
public ProfileManager() {
}
public ProfileManager(EntityManagerFactory emf) {
this.emf = emf;
}
public void setEntityManagerFactory(EntityManagerFactory emf) {
this.emf = emf;
}
private EntityManager getEntityManager() {
if (emf == null) {
throw new RuntimeException("The EntityManagerFactory is null. This must be passed in to the constructor``");
}
return emf.createEntityManager(); // THIS FAILS
}
}
Log trace;
at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.getStatus(JtaStatusHelper.java:73)
at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.isActive(JtaStatusHelper.java:115)
at org.hibernate.engine.transaction.internal.jta.CMTTransaction.join(CMTTransaction.java:149)
at org.hibernate.ejb.AbstractEntityManagerImpl.joinTransaction(AbstractEntityManagerImpl.java:1207)
at org.hibernate.ejb.AbstractEntityManagerImpl.postInit(AbstractEntityManagerImpl.java:176)
at org.hibernate.ejb.EntityManagerImpl.<init>(EntityManagerImpl.java:89)
at org.hibernate.ejb.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:125)
Edit of Neil; "JtaStatusHelper is a HIBERNATE class!" rang the bell for me. I went and checked the props of emf as the following;
Map<String, Object> prop = emf.getProperties();
logger.debug("emf props : " + prop.toString());
And observed the differences between SIT and UAT environments.
The basic difference was that openjpa was not available in any keys of the prop for SIT while it was all over the places for UAT. The config for SIT was somehow turned into hibernate related lines. However, I was out after having things in place according to JPA settings.
It simply proved that something is wrong with the last installation of the application into Server. Thus, I uninstalled the app and install it from scratch.
It made things right.
The usual idiom I see for creating the EntityManager is something like this:
public class BaseDao {
private static final String PERSISTENCE_UNIT_NAME = "Employee";
EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
public EntityManager getEntityManager() {
return factory.createEntityManager();
}
}
Then it is used like this:
Employee emp = new Employee();
emp.setName("Joe M");
getEntityManager().persist(emp);
Question is why not do it this way:
public class BaseDao{
private static final String PERSISTENCE_UNIT_NAME = "Employee";
EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
private EntityManager entityManager = null;
public void setEntityManger() {
EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
this.entityManager = factory.createEntityManager();
}
public EntityManager getEntityManager() {
return this.entityManager;
}
}
In other words is there a need to always get the entity manager through factory.createEntityManager()? or can it be created as an instance (or even static) variable and retrieved like that?
To clarify, I am talking about an environment that doesn't use EJB or Spring containers.
Thanks.
There are two ways to create EntityManager instances.
One way is for SDK applications, and I use this way a lot in unit testing. This is what you have in your example:
EntityManagerFactory factory =
Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
In Enterprise applications you let the container create them for you and inject them when needed.
EntityManager is just a wrapper around a JDBC connection. It's very light weight and can be created and destroyed without performance penalty.
Keep in mind that the EntityManager is not thread safe, so if you have one instance, you may need to synchronize access to it. See transaction basics for details.
Here's how I would do it (roughly):
public class BaseDao{
private static final String PERSISTENCE_UNIT_NAME = "Employee";
private static EntityManagerFactory factory =
Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
public void create(MyEntiy person){
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
// do what ever you need
em.getTransaction().commit();
em.close();
}
// add more methods to the dao.
}
Once you get this protoyped and ready, you can use a generic DAO.
Today you should probably look at sometime like spring-data and #PersistanceUnit for managing your EntityManager.
An EntityManager is more than just a wrapper a wrapper for a JDBC connection. It defines the scope of a persistence context, which defines the unit of work that should be performed when a transaction is committed (of when you flush queries to the database). Within a persistence context you are also guaranteed that a given entity in the database will result in the same Java object, regardless if you load it directly, or access it through a OneToMany relation of another entity.
With regards to the original question about obtaining an EntityManagerFactory in a non-spring setting. You simply call
Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
This method is a static factory method, depending on your JPA implementation you either get the same instance for the same PU, or a shallow wrapper that wraps the underlying persistence session (of which there is one per PU).
Scenario:
I have #Singleton UserFactory (#Stateless could be) , its method createSession() generating #Stateful UserSession bean by manual lookup.
If I am injecting by DI #EJB - i will get same instance during calling fromFactory() method(as it should be)
What I want - is to get new instance of UserSession without preforming lookup.
Q1: how could I call new instance of #Stateful session bean?
Code:
#Singleton
#Startup
#LocalBean
public class UserFactory {
#EJB
private UserSession session;
public UserFactory() {
}
#Schedule(second = "*/1", minute = "*", hour = "*")
public void creatingInstances(){
try {
InitialContext ctx = new InitialContext();
UserSession session2 = (UserSession) ctx.lookup("java:global/inferno/lic/UserSession");
System.out.println("in singleton UUID " +session2.getSessionUUID());
} catch (NamingException e) {
e.printStackTrace();
}
}
#Schedule(second = "*/1", minute = "*", hour = "*")
public void fromFactory(){
System.out.println("in singleton UUID " +session.getSessionUUID());
}
public UserSession creatSession(){
UserSession session2 = null;
try {
InitialContext ctx = new InitialContext();
session2 = (UserSession) ctx.lookup("java:global/inferno/lic/UserSession");
System.out.println("in singleton UUID " +session2.getSessionUUID());
} catch (NamingException e) {
e.printStackTrace();
}
return session2;
}
}
As I understand, calling of
session.getClass().newInstance();
is not a best idea
Q2 : is it true?
#
Update
Goals
In reality the goal is to create some SessionsFactory that that would managed user`s sessions (this is web services users)
The Session #Statefull bean :
#Stateful
//Destroying outomaticly after 30 minuts inactive
#StatefulTimeout(180000)
#LocalBean
public class UserSession {
//represent creation time, used by scheduler for destroying session
private GregorianCalendar creationDate;
private UUID sessionUUID;
private String userId;
private String state;
//TODO change to xml
private String histrory;
public UserSession() {
}
#PostConstruct
private void initSession(){
//getting construction date
creationDate = (GregorianCalendar) Calendar.getInstance();
//generationg session id
sessionUUID = UUID.randomUUID();
}
#PreDestroy
private void releaseResource(){
creationDate =null;
sessionUUID = null;
userId =null;
}
#Remove
public void destroySession(){
}
public UUID getSessionUUID() {
return sessionUUID;
}
public GregorianCalendar getCreationDate() {
return creationDate;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getHistrory() {
return histrory;
}
public void addHistroryEntry(String entry) {
//TODO add history entry
}
}
In factory methods I want just create new instance of #Statefull UserSession and to manage number of created sessions for each user, and call destroySession() after some period (30 minutes)
I need to track the history of user`s sessions requests , and persists there history later..
So I think #Statefull bean should suet my needs. But it looks like the lookup by JNDI name is the only chance to be shore that new ejb will be created. I am searching for possibility
to inject new instance of ejb without lookups, and maybe possibility to get collection of currently created instances of my #Statefull UserSession instead of keeping thrm in some map/collection.
Q3: so.. only JNDI will help me to create new instance of ejb ?
Q4: Is it possible to get collection of some ejb`s instances from container?
I am using glassfish v3, ejb 3.1.
Q1: how could I call new instance of #Stateful session bean?
You must not inject a Stateful Session Bean into a stateless object such as Stateless
Session Bean or Servlet that may be shared by multiple concurrent clients, you should use JNDI instead. Period.
To be honest, I'm not sure to understand what you are doing and I don't see important steps such as removal of your Stateful Session Beans. You are likely going to run out of memory or cause a lot of disk IO as the container that will try to passivate/activate instances to save memory.
Q2 : is it true?
You can call new but don't expect to get something else than a simple Java class i.e. don't expect to get a managed object i.e. don't expect to get an EJB. I don't think that this is what you want.
Sorry if this doesn't help much but as I said, I don't really understand what you're trying to achieve. You should maybe start to explain your goal first, I don't have the feeling that you are on the right path.