与Hibernate一起提交事务时出现ConcurrentModificationException

时间:2016-08-29 09:02:21

标签: 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.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的已知问题吗?

3 个答案:

答案 0 :(得分:6)

异常结果是由我们使用的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);
   }
}

问题也可能表现为StackOverflowError

答案 1 :(得分:3)

我在hibernate 5.0.11中使用了这个,并且验证了它也发生在5.2.5。我的解决方案是注释自定义验证器以打开新事务。

@Transactional(propagation=Propagation.REQUIRES_NEW)

我认为在自定义约束验证器易于设置和使用之前,hibernate仍有一段路要走,因为这花费了我更多的时间。

编辑:问题相关。我认为使用相同的交易违反了jpa2.1规范https://hibernate.atlassian.net/browse/HHH-7537

答案 2 :(得分:0)

在实现ConstraintValidator的类中,我们需要有一个EntityManager实例,但我们不在Spring上下文中,以便自动实现带注释@Autowired的EntityManager对象。因此,在配置包中,我们可以编写一个工厂,它允许拥有一个Application实例,以便在我们不在Spring上下文时实现bean。

@Configuration
public class ApplicationContextConf {

    @Bean
    public static ApplicationContextProvider contextProvider() {
        return new ApplicationContextProvider();
    }

}


@Component
public class ApplicationContextProvider implements ApplicationContextAware {

    private static ApplicationContext context;

    public ApplicationContext getApplicationContext() {
        return context;
    }

    @Override
    public void setApplicationContext(final ApplicationContext ctx) {
        context = ctx;
    }
}


在实现ConstraintValidator的类中,我们实现了一个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);
        }
    }
}