Hibernate SessionFactory vs. JPA EntityManagerFactory
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 theBootstrapServiceRegistryBuilder
. If you're using Spring, the Hibernate bootstrap is done via theLocalSessionFactoryBean
, as illustrated by this GitHub example. - Or, you can create a JPA
EntityManagerFactory
via thePersistence
class or theEntityManagerFactoryBuilder
. If you're using Spring, the JPA bootstrap is done via theLocalContainerEntityManagerFactoryBean
, 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.
精彩评论