Hibernate SessionFactory vs. JPA EntityManagerFactory - java

I am new to Hibernate and I'm not sure whether to use a Hibernate SessionFactory or a JPA EntityManagerFactory to create a Hibernate Session.
What is the difference between these two? What are the pros & cons of using each of those?

Prefer EntityManagerFactory and EntityManager. They are defined by the JPA standard.
SessionFactory and Session are hibernate-specific. The EntityManager invokes the hibernate session under the hood. And if you need some specific features that are not available in the EntityManager, you can obtain the session by calling:
Session session = entityManager.unwrap(Session.class);

SessionFactory vs. EntityManagerFactory
As I explained in the Hibernate User Guide, the Hibernate SessionFactory extends the JPA EntityManagerFactory, as illustrated by the following diagram:
So, the SessionFactory is also a JPA EntityManagerFactory.
Both the SessionFactory and the EntityManagerFactory contain the entity mapping metadata and allow you to create a Hibernate Session or a EntityManager.
Session vs. EntityManager
Just like the SessionFactory and EntityManagerFactory, the Hibernate Session extends the JPA EntityManager. So, all methods defined by the EntityManager are available in the Hibernate Session.
The Session and the `EntityManager translate entity state transitions into SQL statements, like SELECT, INSERT, UPDATE, and DELETE.
Hibernate vs. JPA bootstrap
When bootstrapping a JPA or Hibernate application, you have two choices:
You can bootstrap via the Hibernate native mechanism, and create a SessionFactory via the BootstrapServiceRegistryBuilder. If you're using Spring, the Hibernate bootstrap is done via the LocalSessionFactoryBean, as illustrated by this GitHub example.
Or, you can create a JPA EntityManagerFactory via the Persistence class or the EntityManagerFactoryBuilder. If you're using Spring, the JPA bootstrap is done via the LocalContainerEntityManagerFactoryBean, as illustrated by this GitHub example.
Bootstrapping via JPA is to be preferred. That's because the JPA FlushModeType.AUTO is a much better choice than the legacy FlushMode.AUTO, which breaks read-your-writes consistency for native SQL queries.
Unwrapping JPA to Hibernate
Also, if you bootstrap via JPA, and you have injected the EntityManagerFactory via the #PersistenceUnit annotation:
#PersistenceUnit
private EntityManagerFactory entityManagerFactory;
You can easily get access to the underlying Sessionfactory using the unwrap method:
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
The same can be done with the JPA EntityManager. If you inject the EntityManager via the #PersistenceContext annotation:
#PersistenceContext
private EntityManager entityManager;
You can easily get access to the underlying Session using the unwrap method:
Session session = entityManager.unwrap(Session.class);
Conclusion
So, you should bootstrap via JPA, use the EntityManagerFactory and EntityManager, and only unwrap those to their associated Hibernate interfaces when you want to get access to some Hibernate-specific methods that are not available in JPA, like fetching the entity via its natural identifier.

I want to add on this that you can also get Hibernate's session by calling getDelegate() method from EntityManager.
ex:
Session session = (Session) entityManager.getDelegate();

I prefer the JPA2 EntityManager API over SessionFactory, because it feels more modern. One simple example:
JPA:
#PersistenceContext
EntityManager entityManager;
public List<MyEntity> findSomeApples() {
return entityManager
.createQuery("from MyEntity where apples=7", MyEntity.class)
.getResultList();
}
SessionFactory:
#Autowired
SessionFactory sessionFactory;
public List<MyEntity> findSomeApples() {
Session session = sessionFactory.getCurrentSession();
List<?> result = session.createQuery("from MyEntity where apples=7")
.list();
#SuppressWarnings("unchecked")
List<MyEntity> resultCasted = (List<MyEntity>) result;
return resultCasted;
}
I think it's clear that the first one looks cleaner and is also easier to test because EntityManager can be easily mocked.

Using EntityManagerFactory approach allows us to use callback method annotations like #PrePersist, #PostPersist,#PreUpdate with no extra configuration.
Using similar callbacks while using SessionFactory will require extra efforts.
Related Hibernate docs can be found here and here.
Related SOF Question and Spring Forum discussion

By using EntityManager, code is no longer tightly coupled with hibernate. But for this, in usage we should use :
javax.persistence.EntityManager
instead of
org.hibernate.ejb.HibernateEntityManager
Similarly, for EntityManagerFactory, use javax interface. That way, the code is loosely coupled. If there is a better JPA 2 implementation than hibernate, switching would be easy. In extreme case, we could type cast to HibernateEntityManager.

EntityManagerFactory is the standard implementation, it is the same across all the implementations. If you migrate your ORM for any other provider like EclipseLink, there will not be any change in the approach for handling the transaction. In contrast, if you use hibernate’s session factory, it is tied to hibernate APIs and cannot migrate to new vendor.

EntityManager interface is similar to sessionFactory in hibernate.
EntityManager under javax.persistance package but session and sessionFactory under org.hibernate.Session/sessionFactory package.
Entity manager is JPA specific and session/sessionFactory are hibernate specific.

Related

Do session and entity manager refer to the same persistence context, or do they have their own implementation?

I have a important question related to Session and EntityManager in hibernate. I know that through either the session object or entitymanager object you can talk to the persistence context. My question is that when you use either one, the session object or entity manager object, will the persistence context you are talking to be the same in both cases? For instance lets imagine(hypothetically) there is a concrete implementation called PersistenceContext then if I use either session or entitymanager, will they both be referring to an instance of PersistanceContext when I use methods like session.get(), or entityManager.find(), or do they both have their own implementation of PersistanceContext?
Edit:
I'm using version 4.3 and up and I am obtaining session and EntityManager via SessionFactory and EntityManagerFactory.

Using session object to create CriteriaBuilder to create a CriteriaQuery since CriteriaAPI is deprecated

I'm learing Hibernate and have already built a project using Hibernate and I've created a SessionFactory object and then a Session object using the SessionFactory's openSession method.
While trying to use Criteria API of Hibernate I found that it has been deprecated since 5.2.3 Final version which I'm using.
I do not want to create an EntityManager object using EntityManagerFactory as I'm already using SessionFactory.
This is what I've done.
---
try (Session session = HibernateUtil.getSessionfactory().openSession()) {
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
session.beginTransaction();
CriteriaQuery<Transaction> criteriaQuery = criteriaBuilder.createQuery(Transaction.class);
Root<Transaction> root = criteriaQuery.from(Transaction.class);
criteriaQuery.select(root);
List<Transaction> transactions = session.createQuery(criteriaQuery).getResultList();
for (Transaction transaction : transactions) {
System.out.println(transaction.getTitle());
}
---
This surely isn't the optimal way to do it as Hibernate is built on top of JPA and the best way to do it would be using EntityManager. Is there any other workaround to what I'm doing instead of having to create an EntityManagerFactory and then a EntityManager object using the said factory as It would mean I'd have to make a lot of other changes to the program design.
As I can see, unfortunatelly there is no such an API which replaces the Criteria API in Hibernate. Please consult the 5.1 documentaion which explains it.
I also wanted to use SessionFactory instance to handle queries but it is recommanded to use EntityManager for building queries programatically.

What does EntityManager::getDelegate return?

I am using JBoss 7 with the default Hibernate JPA engine in an EJB3 / JSF project.
The javadoc on EntityManager::getDelegate reads: "Return the underlying provider object for the EntityManager, if available.".
Out of curiosity I tried the following code:
#Stateless
public class AFacade {
#PersistenceContext(unitName="foo")
EntityManager em;
public List<A> findAll() {
l.info("underlying entity manager is: "+em.getDelegate().getClass().getSimpleName());
...
}
The output however indicates the classname as: org.hibernate.internal.SessionImpl which, according to hibernate documentation is a Session implementation.
What am I missing here ?
JPA is just a specification for ORM; there are some implementations for this specification/API the most known being Hibernate, EclipseLink, OpenJPA.
This means that the EntityManager is just an adapter to a class from the implementation library. In your case it is org.hibernate.internal.SessionImpl since you use Hibernate as a JPA implementation - this is the class that manages the code you give to the EntityManager.

How can I receive the persistence unit name of an EntityManager?

In a Java EE application I am using #PersistenceContext on an EJB3.0 SessionBean to let an EntityManager be autowired.
As I am using multiple Datasources, I want to programmatically determine the autowired PersistenceUnit name of the EntityManager. Any chance?
You can retrieve more than one entity manager in this way:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("name your PU")
EntityManager em = emf.createEntityManager();
...
em.close();
emf.close();
But I do not know if a good solution. Annotation #PersistenceContext allows retrieve only one entity manager. But you may try create one class/stateless bean which will keep more than one PU, and take from him PU which you need. Maybe this little better than use EntityManagerFactory.

Hibernate EntityManagerFactory EntityManager

Can I create an EntityManager from EntityManagerFactory outside a bean. If so, how would I do it?
In a non-managed environment (this is what you mean by outside a bean, right?), then you typically use:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("MyPu");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin()
...
em.getTransaction().commit();
emf.close();
Check the other factory method allowing to pass properties as parameter (they will override any values that may have been configured elsewhere): Persistence.createEntityManagerFactory(String, Map).
See also
Using the Java Persistence API in Desktop Applications
An Introduction to Java Persistence for Client-Side Developers

Categories

Resources