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.
Data Engineering Design Patterns

Looking for a book that defines and solves most common data engineering problems? I wrote
one on that topic! You can read it online
on the O'Reilly platform,
or get a print copy on Amazon.
I also help solve your data engineering problems 👉 contact@waitingforcode.com 📩
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.
Consulting

With nearly 16 years of experience, including 8 as data engineer, I offer expert consulting to design and optimize scalable data solutions.
As an O’Reilly author, Data+AI Summit speaker, and blogger, I bring cutting-edge insights to modernize infrastructure, build robust pipelines, and
drive data-driven decision-making. Let's transform your data challenges into opportunities—reach out to elevate your data engineering game today!
👉 contact@waitingforcode.com
đź”— past projects