在 OptimisticLockException - org.postgresql.util.PSQLException 之后重试方法时出错:此语句已关闭
Error when retrying method after OptimisticLockException - org.postgresql.util.PSQLException: This statement has been closed
我有方法:
public void changeItemName(long id, String nmae) {
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());
itemDAO.clear();
changeItemName(id, name);
}
}
首先,我通过设置更高版本手动触发 OptimisticLockException
,因此它会进入 catch 块,清除 EntityManager
并重试该方法。重试时,object/entity 已刷新且版本正确,但我得到:
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)
数据库模块(使用 Guice 4.1.0):
public class DbModule extends PrivateModule {
@Override
public void configure() {
install(new JpaPersistModule("persistence-unit").properties(jpaProperties()));
...
Key<PersistFilter> key = Key.get(PersistFilter.class, ExamplePersistenceUnit.class);
bind(key).to(PersistFilter.class);
expose(key);
}
保存方法实现(使用Hibernate 5.1.0.Final):
@Inject
protected EntityManager entityManager;
@Override
public void save(T entity) {
entityManager.getTransaction().begin();
entityManager.persist(entity);
entityManager.getTransaction().commit();
}
为什么会这样?
更新
经过一些调试,我注意到:
- 第一个方法调用 - 我得到
OptimisticLockException
/ StaleStateException
- 没关系,它是有意提出和预期的
- 第二次方法调用,重试,我得到
Caused by: org.postgresql.util.PSQLException: This statement has been closed
- 这个是意外的
- 第三次方法调用,再次重试 - 它运行良好并成功保存到数据库
全部 3 次,使用相同的 EntityManager entityManager
实例。
我也遇到了同样的问题,在@Jonathan 的评论帮助下,我使用以下方法解决了这个问题:
@Retryable(include = {ObjectOptimisticLockingFailureException.class, JpaSystemException.class}, backoff=@Backoff(delay = 100))
另见精彩问答:
我有方法:
public void changeItemName(long id, String nmae) {
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());
itemDAO.clear();
changeItemName(id, name);
}
}
首先,我通过设置更高版本手动触发 OptimisticLockException
,因此它会进入 catch 块,清除 EntityManager
并重试该方法。重试时,object/entity 已刷新且版本正确,但我得到:
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)
数据库模块(使用 Guice 4.1.0):
public class DbModule extends PrivateModule {
@Override
public void configure() {
install(new JpaPersistModule("persistence-unit").properties(jpaProperties()));
...
Key<PersistFilter> key = Key.get(PersistFilter.class, ExamplePersistenceUnit.class);
bind(key).to(PersistFilter.class);
expose(key);
}
保存方法实现(使用Hibernate 5.1.0.Final):
@Inject
protected EntityManager entityManager;
@Override
public void save(T entity) {
entityManager.getTransaction().begin();
entityManager.persist(entity);
entityManager.getTransaction().commit();
}
为什么会这样?
更新
经过一些调试,我注意到:
- 第一个方法调用 - 我得到
OptimisticLockException
/StaleStateException
- 没关系,它是有意提出和预期的 - 第二次方法调用,重试,我得到
Caused by: org.postgresql.util.PSQLException: This statement has been closed
- 这个是意外的 - 第三次方法调用,再次重试 - 它运行良好并成功保存到数据库
全部 3 次,使用相同的 EntityManager entityManager
实例。
我也遇到了同样的问题,在@Jonathan 的评论帮助下,我使用以下方法解决了这个问题: @Retryable(include = {ObjectOptimisticLockingFailureException.class, JpaSystemException.class}, backoff=@Backoff(delay = 100))
另见精彩问答: