Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA concurrency issue "On release of batch it still contained JDBC statements"

I have a a concurrency issue I tried to solve with a while loop that attempts to save an entity multiple times until it hits some max retry count. I'd like to avoid talking about whether or not there are other ways to solve this problem. I have other Stackoverflow posts about that. :) Long story short: there's a unique constraint on a column that is derived and includes a numeric portion that keeps incrementing to avoid collisions. In a loop, I:

  1. select max(some_value)
  2. increment the result
  3. attempt to save new object with this new result
  4. explicitly flush the entity and, if that fails because of the unique index, I catch a DataAccessException.

All of this seems to work except when the loop goes back to step 1 and tries to select, I get:

17:20:46,111 INFO  [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl] (http-localhost/127.0.0.1:8080-3) HHH000010: On release of batch it still contained JDBC statements
17:20:46,111 INFO  [my.Class] (http-localhost/127.0.0.1:8080-3) MESSAGE="Failed to save to database. Will retry (retry count now at: 9) Exception: could not execute statement; SQL [n/a]; constraint [SCHEMA_NAME.UNIQUE_CONSTRAINT_NAME]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"

And a new Exception is caught. It seems like the first flush that causes the unique constraint violation and throws the DataAccessException doesn't clear the entity manager's batch. What's the appropriate way to deal with this? I'm using Spring with JPA and don't have direct access to the entity manager. I guess I could inject it if I need it but that's a painful solution to this problem.

like image 341
Chris Williams Avatar asked Sep 27 '16 21:09

Chris Williams


2 Answers

You cannot do that - once you flush something and it fails and an exception is thrown, the transaction will be marked as roll back. That means it doesnt matter that you catch the exception and proceed, you'll end up with a rollback. Actually it doesnt matter at all what exception was thrown - by default Spring's transaction manager will rollback on every unchecked exception. You can overcome it by specifically defining a noRollbackFor on the @Transactional annotation (providing you are using annotation driver transactions)

Edit - it also won't help you in case of this constraint violation, since the transaction will be probably marked as rollback at the database level.

like image 169
paranoidAndroid Avatar answered Sep 19 '22 12:09

paranoidAndroid


I found this question getting same error. In my case the problem was caused by weird combination of trigger and row lock (see PSQLException and lock issue when trigger added on table). However it took some time to discover this error is just consequence of primary error, not the cause. When Hibernate flushes session and some constraint violation happens, it receives some JDBC exception and in the finally block it tries to call abortBatch. When any statement remains in session, Hibernate emits this warning, though the actual error should be search for somewhere before.

like image 32
Tomáš Záluský Avatar answered Sep 17 '22 12:09

Tomáš Záluský