I use Java 8, Hibernate 5.1.0.Final, Guice 4.1.0, Jersey 1.19. I have several REST methods which may modify the same object - entity loaded from the database. When they run concurrently and modify the same item, I get:
javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:86)
Caused by: javax.persistence.OptimisticLockException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
Possible solutions:
- Synchronization by object in REST methods
- Constantly refresh object state to reduce chance of
OptimisticLockException
(5 Common Hibernate Exceptions and How to Fix Them) - Retry REST method after
OptimisticLockException
(JPA: pattern for handling OptimisticLockException)
Are there any other options? What's the best way to handle this problem?
UPDATE 1
I have tried to implemented retry:
public void changeItemName(Long id, String name){
Item item = itemDAO.find(id);
item.setName(name);
try {
itemDAO.save(item);
} catch (RollbackException | OptimisticLockException | StaleStateException e) {
logger.warn("Retry method after " + e.getClass().getName());
changeItemName(id, name);
}
}
But I get:
javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:86)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not update: [com.example.Item#1]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692)
Caused by: org.hibernate.exception.GenericJDBCException: could not update: [com.example.Item#1]
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
Caused by: org.postgresql.util.PSQLException: This statement has been closed.
at org.postgresql.jdbc2.AbstractJdbc2Statement.checkClosed(AbstractJdbc2Statement.java:2653)