Hibernate version:
hibernate-entitymanager-3.3.1.jar
Name and version of the database you are using:
Postgres 8.3
The following code works for me. It uses some of my own utilities, but I hope the gist of it is clear. It persists a "vote" object unless doing so violates a unique constraint in which case the existing object is loaded and modified and then merged.
It's the standard insert-then-update-if-it-exists paradigm.
However, there is one problem. When the exception is thrown it always logs an error message even though I catch the error and do something else. I cannot stop the error message from being logged without turning off all hibernate error logging.
Code:
try {
DbUtils.useTransaction(em.getTransaction(), new TxAction() {
@Override
public void run() {
em.persist(vote);
}
});
} catch(Exception e) {
Query voteQuery = em.createQuery("FROM Vote WHERE billAction=:billAction and voter=:voter");
voteQuery.setParameter("billAction",billAction);
voteQuery.setParameter("voter",voter[0]);
final Vote vote2 = DbUtils.getSingleResult(voteQuery);
vote2.setChoice(choice);
DbUtils.useTransaction(em.getTransaction(), new TxAction() {
@Override
public void run() {
em.merge(vote2);
}
});
}
The following error message is output every single time the persist throws an exception even though I catch it and do not log it.
Code:
5530502 [pool-1-thread-51] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 0, SQLState: null
5530502 [pool-1-thread-51] ERROR org.hibernate.util.JDBCExceptionReporter - Batch entry 0 insert into who.Vote (billAction, choice, voter, id) values (12524, 1, 12299, 4257365) was aborted. Call getNextException to see the cause.
5530502 [pool-1-thread-51] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 0, SQLState: 23505
5530502 [pool-1-thread-51] ERROR org.hibernate.util.JDBCExceptionReporter - ERROR: duplicate key value violates unique constraint "votebillactionvoter"
5530512 [pool-1-thread-51] ERROR org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:237)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
at com.knowlist.utils.db.DbUtils.useTransaction(DbUtils.java:76)
at whoelect.vote.VoteService.changeVote(VoteService.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.directwebremoting.impl.ExecuteAjaxFilter.doFilter(ExecuteAjaxFilter.java:34)
at org.directwebremoting.impl.DefaultRemoter$1.doFilter(DefaultRemoter.java:428)
at org.directwebremoting.impl.DefaultRemoter.execute(DefaultRemoter.java:431)
at org.directwebremoting.impl.DefaultRemoter.execute(DefaultRemoter.java:283)
at org.directwebremoting.servlet.PlainCallHandler.handle(PlainCallHandler.java:52)
at org.directwebremoting.servlet.UrlProcessor.handle(UrlProcessor.java:101)
at org.directwebremoting.servlet.DwrServlet.doPost(DwrServlet.java:146)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at com.knowlist.num.servlet.EntityManagerFilter.doFilter(EntityManagerFilter.java:79)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:726)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:206)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:842)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:648)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.sql.BatchUpdateException: Batch entry 0 insert into who.Vote (billAction, choice, voter, id) values (12524, 1, 12299, 4257365) was aborted. Call getNextException to see the cause.
at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleError(AbstractJdbc2Statement.java:2387)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1257)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:334)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2446)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 45 more
As I said before, the above code works. The value is either inserted if it doesn't exist, or the existing row is updated if it does already exist. I just want to stop the superfluous error messages from being logged. Or, alternatively, I'd be happy to use some other method of doing all this if there is a better way to do it using JPA and hibernate.