Java 使用Hibernate提交事务时的ConcurrentModificationException
在我们的应用程序中,我们已经从Hibernate 3.5.6-final升级到4.2.21.final,现在我们在提交数据库事务时得到了一个Java 使用Hibernate提交事务时的ConcurrentModificationException,java,hibernate,Java,Hibernate,在我们的应用程序中,我们已经从Hibernate 3.5.6-final升级到4.2.21.final,现在我们在提交数据库事务时得到了一个ConcurrentModificationException: java.util.ConcurrentModificationException: null at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) at java.util.ArrayLis
ConcurrentModificationException
:
java.util.ConcurrentModificationException: null
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:386)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:304)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:349)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1195)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
这是Hibernate 4.2的一个已知问题吗?这个异常是由我们使用的Hibernate自定义约束验证器的问题引起的。验证程序的
isValid
正在运行Hibernate条件查询。该查询触发了Hibernate会话刷新,导致出现ConcurrentModificationException
。我们通过在isValid
方法中临时禁用自动刷新来修复此问题:
@Override
public boolean isValid(Object object, final ConstraintValidatorContext c) {
try {
sessionFactory.getCurrentSession().setFlushMode(FlushMode.MANUAL);
...
} finally {
sessionFactory.getCurrentSession().setFlushMode(FlushMode.AUTO);
}
}
这个问题也可能表现为一个
堆栈溢出错误
我在hibernate 5.0.11中遇到了这个问题,并在5.2.5中验证了它的存在。我的解决方案是注释自定义验证器以打开新事务
@Transactional(propagation=Propagation.REQUIRES_NEW)
我想在自定义约束验证器易于设置和使用之前,hibernate还有一段路要走,因为这花费了我更多的时间
编辑:与问题相关。我认为,在实现ConstraintValidator的类中,使用相同的事务违反了jpa2.1规范,我们需要EntityManager的实例,但我们不在Spring上下文中,以便使用注释@Autowired自动实例化EntityManager对象。因此,在配置包中,我们可以编写一个工厂,它允许有一个应用程序实例,以便在不在Spring上下文中时实例化bean
@Configuration
public class ApplicationContextConf {
@Bean
public static ApplicationContextProvider contextProvider() {
return new ApplicationContextProvider();
}
}
在实现ConstraintValidator的类中,由于前面在initialize方法中创建的工厂,我们实例化了EntityManager 在调用调用存储库的方法之前,我们将Hibernate当前会话的刷新模式更改为FlushMode.MANUAL,以避免在调用存储库后自动刷新,同时保持默认刷新模式。最后,在块中,我们恢复先前保留的刷新模式的默认值
private EntityManager entityManager;
@Override
public void initialize(final Object object ) {
// ...
try {
this.entityManager = ApplicationContextConf
.contextProvider()
.getApplicationContext()
.getBean(EntityManager.class);
}
catch (final BeansException ex) {
// ...
}
}
@Override
public boolean isValid(final Object object, final ConstraintValidatorContext context) {
Session hibernateSession = null;
FlushMode originalFlushMode = null;
try {
hibernateSession = this.entityManager.unwrap(Session.class);
originalFlushMode = hibernateSession.getFlushMode();
hibernateSession.setFlushMode(FlushMode.MANUAL);
// ...
}
finally {
if (hibernateSession != null) {
hibernateSession.setFlushMode(originalFlushMode);
}
}
}
您是否使用实体事件侦听器进行了一些自定义工作(persit前或persist后),您需要将代码缩进(至少)4个空格以将其格式化。请在回答中添加一些解释。
private EntityManager entityManager;
@Override
public void initialize(final Object object ) {
// ...
try {
this.entityManager = ApplicationContextConf
.contextProvider()
.getApplicationContext()
.getBean(EntityManager.class);
}
catch (final BeansException ex) {
// ...
}
}
@Override
public boolean isValid(final Object object, final ConstraintValidatorContext context) {
Session hibernateSession = null;
FlushMode originalFlushMode = null;
try {
hibernateSession = this.entityManager.unwrap(Session.class);
originalFlushMode = hibernateSession.getFlushMode();
hibernateSession.setFlushMode(FlushMode.MANUAL);
// ...
}
finally {
if (hibernateSession != null) {
hibernateSession.setFlushMode(originalFlushMode);
}
}
}