Accessing Hibernate Session from EJB using EntityManager - java

Is it possible to obtain the Hibernate Session object from the EntityManager? I want to access some hibernate specific API...
I already tried something like:
org.hibernate.Session hSession =
( (EntityManagerImpl) em.getDelegate() ).getSession();
but as soon as I invoke a method in the EJB I get "A system exception occurred during an invocation on EJB" with a NullPointerException
I use glassfish 3.0.1

Bozho and partenon are correct, but:
In JPA 2, the preferred mechanism is entityManager.unwrap(class)
HibernateEntityManager hem = em.unwrap(HibernateEntityManager.class);
Session session = hem.getSession();
I think your exception is caused because you are trying to cast to an implementation class (perhaps you were dealing with a JDK proxy). Cast to an interface, and everything should be fine (in the JPA 2 version, no casting is needed).

From Hibernate EntityManager docs, the preferred way of doing it is:
Session session = entityManager.unwrap(Session.class);

As simple as:
Session session = (Session) em.getDelegate();

If your EntityManager is properly injected (using #PersistenceContext) and is not null, then the following should work:
org.hibernate.Session hSession = (Session) em.getDelegate();

Related

Does Hibernate query caching have any effect if it's used as a JPA provider only? [duplicate]

This question already has an answer here:
Will hibernate cache (EHCache for eg) will work with jpa specific code (if I use EntityManager/EM Factory instead of Session/SessionFactory)?
(1 answer)
Closed 5 years ago.
Hibernate offers to select different cache providers for query and L2 caching, but there seems to be no clear statement whether this has an effect if Hibernate is used as plain JPA provider only, i.e. by running queries with EntityManager instead of Session. All introductions simply speak of Hibernate which can mean Hibernate with Hibernate-specific features or Hibernate as JPA provider and then provide code examples involving Hibernate - to advertise the use or because it's a necessity?
In case that matters, I'm referring to a Java EE environment.
Use of the caching provider is only a matter of configuration of Hibernate. EntityManager is only thin wrapper around Session. FYI since Hibernate version 5.2 Session extends EntityManager, see https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/Session.html .
So answer is - Hibernate uses all of their power even when used through JPA.
EDIT:
You can ensure that EntityManager is wrapper around Session by code like this:
EntityManager em = ...; // Get EntityManager from somewhere
Session session = em.unwrap(Session.class);
If you use Hibernate then you will successefully get session wrapped by EntityManager and can to use it directly.

Hibernate random "Session is closed error" with 2 databases

I have a requirement to use 2 different databases within single DAO class. One of the databases is read/write while the other is read only.
I have created 2 data sources, 2 session factories and 2 transaction managers (transaction manager for the read/write database is the platform transaction manager) for these databases. I am using #Transactional on the service method to configure Spring for transaction management.
We are getting random Session is closed! exceptions when we call sessionFactory.getCurrentSession() in the DAO class ( I can not always produce it, it sometimes works ok, sometimes gets error) :
org.hibernate.SessionException: Session is closed!
at org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:133)
at org.hibernate.internal.SessionImpl.setFlushMode(SessionImpl.java:1435)
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:99)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
I don't have a requirement to use global transaction (XA), I just want to query 2 different databases.
I have read this thread, it suggests injecting two separate session factories in the DAO layer as we do now: Session factories to handle multiple DB connections
Also AbstractRoutingDataSource does not work for single Dao class as per this answer: https://stackoverflow.com/a/7379048/572380
Example code from my dao looks like this:
Criteria criteria = sessionFactory1.getCurrentSession().createCriteria(MyClass.class);
criteria.add(Restrictions.eq("id", id));
criteria.list();
criteria = sessionFactory2.getCurrentSession().createCriteria(MyClass2.class); // generates random "Session is closed!" error.
criteria.add(Restrictions.eq("id", id));
criteria.list();
I have also tried using "doInHibernate" method. But the session passed to it is also randomly throwing "Session is closed!" exceptions:
#Autowired
protected HibernateTemplate hibernateTemplate;
#SuppressWarnings("unchecked")
protected List<Map<String, Object>> executeStaticQuery(final String sql) {
HibernateCallback<List<Map<String, Object>>> hibernateCallback = new HibernateCallback<List<Map<String, Object>>>() {
#Override
public List<Map<String, Object>> doInHibernate(Session session) throws HibernateException {
SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
return query.list();
}
};
return hibernateTemplate.execute(hibernateCallback);
}
So you do have the below code in your application? If you don't you should add it,might be it is causing the problem.
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven/>
Remove this property as mentioned below
<property name="current_session_context_class">thread</property>
You are overriding Spring which sets this to SpringSessionContext.class. This is almost certainly at least part of your problem.
Spring manages your session objects. These session objects that it manages are tied to Spring transactions. So the fact that you are getting that error means to me that it is most likely due to how you are handling transactions.
in other words don't do this
Transaction tx = session.beginTransaction();
unless you want to manage the life cycle of the session yourself in which case you need to call session.open() and session.close()
Instead use the framework to handle transactions. I would take advantage of spring aspects and the declarative approach using #Transactional like I described earlier its both cleaner and more simple, but if you want to do it pragmatically you can do that with Spring as well. Follow the example outlined in the reference manual. See the below link:
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/orm.html#orm-hibernate-tx-programmatic
Above error suggest, you are not able to get the session as session is closed sometimes. You can use openSession() method instead of getCurrentSession() method.
Session session = this.getSessionFactory().openSession();
session.beginTransaction();
// Your Code Here.
session.close();
Drawback with this approach is you will explicitly need to close the session.
In single threaded environment it is slower than getCurrentSession().
Check this Link Also:- Hibernate Session is closed
The problem is that you have a single hibernate session and two data stores. The session is bound to the transaction. If you open a new transaction towards the other database this will effectively open a new session for this database and this entity manager.
this is equivalent to #Transactional(propagation = Propagation.REQUIRES_NEW)
You need to ensure that there are two different transactions/sessions bound to each of the persistent operations towards the two databases.
If all configurations are correct, then every thing should work fine without error
I think you missed #Qualifier(value="sessionFactory1") and #Qualifier(value="sessionFactory2") at your DAO
kindly look at those examples
Hibernate configuring multiple datasources and multiple session factories
https://medium.com/#joeclever/using-multiple-datasources-with-spring-boot-and-spring-data-6430b00c02e7
HibernateTemplate usage is discouraged already. The clear explanation is given here https://stackoverflow.com/a/18002931/1840818
As stated over there, declarative transaction management has to be used.

No session currently bound to execution context

I got below exception when I used session.getCurrentSession().
I have mentioned
hibernate.current_session_context_class: managed
org.hibernate.HibernateException: No session currently bound to execution context
at org.hibernate.context.internal.ManagedSessionContext.currentSession(ManagedSessionContext.java:75)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
at io.dropwizard.hibernate.AbstractDAO.currentSession(AbstractDAO.java:36)
at io.dropwizard.hibernate.AbstractDAO.persist(AbstractDAO.java:149)
I use this with dropwizard. Can anyone help me to solve this?
If you are using Dropwizard Hibernate. You need to add #UnitOfWork annotation to your Resource method. More info within dropwizard manual, hibernate chapter.
Can you try with : session.openSession() - It tell hibernate to always opens a new session and you have to close once you are done with the operations. With session.getCurrentSession(), hibernate returns a session bound to a context that you don't need to close and only need to set the hibernate.current_session_context_class to thread.
You can also configure session with SpringSessionContext, if your application is Spring based.
Edit your hibernate-cfg.xml with below line:
hibernate.current_session_context_class=org.springframework.orm.hibernate3.SpringSessionContext
What above line will do?
Making session context class as "org.springframework.orm.hibernate3.SpringSessionContext
", Hibernate will assume it is executing inside of a Spring transactional context (i.e. through a Spring transactional aspect) and Spring will now manage your transaction for you. However if you call getCurrentSession() outside of such a context, Hibernate will throw an exception complaining that no Session is bound to the thread.

EclipseLink: how to obtain instance of Project class so I can call setDefaultQueryResultsCachePolicy

In EclipseLink 2.5.2, how can I obtain the instance of the org.eclipse.persistence.sessions.Project class that is associated with my existing PersistenceUnit / EntityManagerFactory so that I can call setDefaultQueryResultsCachePolicy?
Thanks.
You can get it from Session, and you can get Session from EntityManager.
// EntityManagerImpl is from package org.eclipse.persistence.internal.jpa
Session session = ((EntityManagerImpl) entityManager).getActiveSession();
Project project = session.getProject();

EntityManager obtained from JNDI lookup is already closed

For (Glassfish v2.1), two RuntimeExceptions from two separate requests from a session bean:
"org.hibernate.SessionException: Session is closed!"
org.hibernate.SessionException: Session is closed!
at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:72)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1138)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:67)
[wrapped] javax.persistence.PersistenceException: org.hibernate.SessionException: Session is closed!
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:76)
"java.lang.IllegalStateException: EntityManager is closed"
java.lang.IllegalStateException: EntityManager is closed
at org.hibernate.ejb.EntityManagerImpl.close(EntityManagerImpl.java:97)
at com.sun.enterprise.util.QueryWrapper.clearDelegates(QueryWrapper.java:460)
at com.sun.enterprise.util.QueryWrapper.getResultList(QueryWrapper.java:198)
Both of these EntityManagers were obtained via JNDI lookup (java:comp:/env/TargetSitePersistenceContext)
Using JTA (transaction-type attribute is not defined in persistence.xml).
& SQL Server 2008 w/ sqljdbc4.jar
The code just does the ff:
query = entityManager.createQuery();
query.getResultList();
And that's it. If I'm not mistaken, I believe the app container will handle open/commit/rollback/close, so we shouldn't have any entityManager.close().
What might have caused those two runtime exceptions?
When does GF actually open/close an EntityManager?
Is there any difference between:
an EntityManager obtained via JNDI lookup
via #PersistenceContext Injection? (So far not issues with this style)
All things being equal, a #PersistenceContext injection and a JNDI lookup should return the same EntityManager. So it might be a bug of GlassFish and you might want to reach for them. But make sure to give all the context like type of session bean used for injection, transaction or not etc etc.
Mark your bean with annotation #TransactionAttribute
#Stateless
#TransactionAttribute(TransactionAttributeType.MANDATORY)
public class Repo implements IRepo
{
container managed transaction is regulated by this parameter

Categories