Hibernate javax.persistence.RollbackException: Error while committing the transaction

hibernate, java, jpa, mysql

Solution

The problem might be that you have a single EntityManager shared by all Web requests. EntityManager is not thread safe. The standard approach in a webapp is to create a new instance of EntityManager for each request. It is ok to have a shared EntityManagerFactory, but not a shared EntityManager.

From the Hibernate doc:

An EntityManager is an inexpensive, non-threadsafe object that should be used once, for a single business process, a single unit of work, and then discarded. An EntityManager will not obtain a JDBC Connection (or a Datasource) unless it is needed, so you may safely open and close an EntityManager even if you are not sure that data access will be needed to serve a particular request.

Problem

I am developing a java web application using Hibernate and MySQL. Sometimes when I try to persist things, I get this rollback exception: ``` javax.persistence.RollbackException: Error while committing the transaction at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:94) at com.tulips.dao.CommentDao.saveOrUpdate(CommentDao.java:42) at com.tulips.servlets.CommentsServlet.doPost(CommentsServlet.java:168) at javax.servlet.http.HttpServlet.service(HttpServlet.java:646) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Caused by: java.lang.NullPointerException at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:155) at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:91) at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:55) at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222) at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425) at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101) at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177) at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77) ... 23 more ``` here is my persistence.xml file : ``` <?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <persistence-unit name="licenta_pu" transaction-type="RESOURCE_LOCAL"> <!-- <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> --> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/tulips"/> <property name="hibernate.connection.username" value="...." /> <property name="hibernate.connection.password" value="...." /> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/> <property name="hibernate.show-sql" value="false" /> <!-- <property name="hibernate.jdbc.batch_size" value="1000" /> --> <!-- <property name="hibernate.hbm2ddl.auto" value="update" /> --> </properties> </persistence-unit> </persistence> ``` I've tried changing the hibernate provider but that didn't help :( [org.hibernate.ejb.HibernatePersistence and org.hibernate.jpa.HibernatePersistenceProvider] I don't know exactly how to replicate this error, sometimes I get it, sometimes I don't. I have observed that every time after I restart my computer and run the project in Eclipse, and try to persist data, it works. If I stop the project, eventually add some data into the database via MySQL Workbench, and then run the project again, I get the error. Here is my EntityManagerHolder: ``` public class EntityManagerHolder { private static EntityManagerHolder INSTANCE = new EntityManagerHolder(); private EntityManagerFactory emf; private EntityManager entityManager; public EntityManager getEntityManager() { return entityManager; } public static EntityManagerHolder getInstance() { return INSTANCE; } private EntityManagerHolder() { super(); emf = Persistence .createEntityManagerFactory("licenta_pu"); entityManager = emf.createEntityManager(); } } ``` Here is my GenericDao: ``` import javax.persistence.EntityManager; import javax.transaction.Transactional; import com.tulips.model.AbstractEntity; @Transactional public abstract class GenericDao { protected EntityManager em; public GenericDao(EntityManager em) { this.em = em; } public void saveOrUpdate(AbstractEntity e) { if (e == null) { throw new NullPointerException("Trying to persist a null object"); } em.getTransaction().begin(); if (e.getId() == null) { em.persist(e); } else { em.merge(e); } em.getTransaction().commit(); } } ``` I'm using the following Hibernate libraries: ``` mysql-connector-java-5.1.9.jar; hibernate-commons-annotations-4.0.4.Final.jar; hibernate-core-4.3.4.Final.jar; hibernate-entitymanager-4.3.4.Final.jar; hibernate-jpa-2.1-api-1.0.0.Final.jar; ```

Original source