Difference between SessionFactory and EntityManagerFactory

There are two ways to handle persistence in Hibernate: session and entity manager. Through this article, we'll see the differences between this two mechanisms.

JPA is a standard

Entity manager is a part of JPA specification while Hibernate implements its own solutions based on Session object, to handle persistence. We see already that one from them (JPA) is a standard. Remember that JPA is "only" and API that describes how to handle objects persistence in standardized way. It can have multiple implementations. So, if your application is based on JPA's implementation, you can switch between different implementations at every moment. It's not the case for Hibernate which can but not must be compatible with other persistence solution.

Hibernate can be used in JPA

The next difference are the classes used to manage the persistence. In JPA, we retreive EntityManagerFactory, EntityManager, all situated in javax.persistence package. Hibernate uses its own classes to represent persistence context: SessionFactory, Session. Because JPA's elements are normally the interfaces, theirs implementations can be different (so they can be Hibernate-based too).

In the case of using Hibernate as JPA implementation, we can still use some of Hibernate specific features. In fact, Hibernate's EntityManager implementation invokes Session object under the hood. We can observe it in some of exception logs, for example in article about Locking in Hibernate/JPA, we can see:

javax.persistence.RollbackException: Error while committing the transaction
  at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:92)
  at com.sandboxWebapp.hibernate.locking.LockingSample.pessimisticReadWithWrite(LockingSample.java:117)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:606)
  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
  at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
  at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
  at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
  at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
  at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
  at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
  at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
  at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:606)
  at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray2(ReflectionUtils.java:208)
  at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:159)
  at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:87)
  at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
  at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:95)
Caused by: javax.persistence.LockTimeoutException: could not execute statement
  at org.hibernate.ejb.AbstractEntityManagerImpl.wrapLockException(AbstractEntityManagerImpl.java:1440)
  at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1339)
  at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1310)
  at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:80)
  ... 29 more
Caused by: org.hibernate.exception.LockTimeoutException: could not execute statement
  at org.hibernate.dialect.MySQLDialect$1.convert(MySQLDialect.java:408)
  at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
  at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
  at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
  at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:136)
  at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:58)
  at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3238)
  at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3140)
  at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3470)
  at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:140)
  at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:393)
  at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:385)
  at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:302)
  at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:339)
  at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
  at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1240)
  at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
  at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
  at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
  at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
  ... 29 more
Caused by: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
  at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
  at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
  at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491)
  at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423)
  at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1936)
  at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2060)
  at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2542)
  at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1734)
  at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2019)
  at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1937)
  at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1922)
  at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133)
  ... 44 more

This exceptions represents a lock timeout and uses Hibernate's Session to manage persistence. We can observe it in below fragment:

at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1240)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)

To get Session from EntityManager's implementation in Hibernate, the simple call suffices:

Session session = entityManager.unwrap(Session.class);

Logging of this session object should return us following output:

Hibernate's session is :SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])

Hibernate and JPA methods comparison

But they are not only the differences. Some methods exist in both sides, but they are differently named. Let's start by getting one entity through its identifier. Hibernate's Session uses a method called get while JPA's method is called find.

To detach one entity from persistence context, Hibernate uses evict method. JPA makes the same with more common named function, detach. Attaching object into persistence context is made in two solutions through the method called persist. Both can also refresh the state of entity with refresh method. Hibernate and JPA have another similarity. They can clear the persistence context by invoking clear() method. This call causes that all attached entities become detached. Regarding differences between Session and EntityManager methods, we should note that Session has more methods to analyze its internal state. The single common method is called isOpen and permits to check if Session or EntityManager is open. In additionally, with Session we can check if it's connected (isConnected), contains dirty (corrupted) data (isDirty) or even if handled objects (entities or proxies) are in read-only mode (isReadOnly).

Also queries objects are the same methods but called differently. JPA gets single row by invoking getSingleResult and a list of results with getResultList. Hibernate makes the same with, respectively, uniqueResult and list methods. Hibernates has also some of extra methods to specify the query parameters. Thanks to its setters, we can set one BigInteger, BigDecimal, Binary, Boolean, Byte, String or Date.

This short article described differences and similarities between JPA and Hibernate's Session persistence mechanism. Both are used to do the same, make persist Java's object in database. They achieve it thanks to persistence context which is managed by EntityManager (JPA) and Session (Hibernate) objects. But they are also some similarities in the working. Both can persist entities through persist and clear persistence context through clear methods. In generally, more abstracted and standardized solution is, it's better for the application's portability. Using Hibernate, we can't easily transfer it into another persistence framework. By using JPA's implementation in Hibernate (without Hibernate-specific features), it will be easier.


If you liked it, you should read:

📚 Newsletter Get new posts, recommended reading and other exclusive information every week. SPAM free - no 3rd party ads, only the information about waitingforcode!