JPA 批量插入导致 ConstraintViolationException

JPA batch insert causing ConstraintViolationException

我正在从事主要使用 EJB 和 JPA 的项目,但我遇到了不应发生的 ConstraintViolationException 问题。

首先,我有 MyEntity class 和 @Id 以及一些独特的字段。 我有 @Stateless MyEntityRepository class 和 find() 方法,通过调用 EntityManager get() 方法只是 returns MyEntity(或 null)。 另一个@Stateless bean 是 SaveEntityBean:

@Stateless
public class SaveEntityBean {

    @Inject
    EntityManager em;
    @Inject
    MyEntityRepository repository;

    public void saveEntity(MyEntity me) {
        if(repository.find(me) == null) {
            //the place with ConstraintViolationException
            em.persist(me);
        }
    }
    public void saveEntities(List<...> entities) {
        for(MyEntity me: entities)
            saveEntity(e);
    }
}

并且方法 saveEntities(List<...> entities) 是从另一个 bean 调用的:

@Stateless
@Startup
public class SaveEntityBean {

    @Inject
    SaveEntityBean saveBean;
    //...

    @Schedule(hour = "*", minute = "*", second="*/5")
    @AccessTimeout(unit = TimeUnit.MINUTES, value = 1)
    public void mainLogicMethod() {
        List<MyEntity> entities = io.calculateAndGetEntities();
        saveBean.saveEntities(entities);
    }
}

其中io.calculateAndGetEntities()方法是长IO工作。问题是有时我得到 org.hibernate.exception.ConstraintViolationException 我认为不应该发生,因为我在调用 persist() 方法之前检查了 MyEntityRepository.find(me) != null 条件。 我唯一的想法是提交之间有一些延迟,所以在条件检查中调用 MyEntityRepository.find(me) 方法后,提交发生,紧接着 persist() 方法抛出异常。

请给我任何阅读和学习以及如何解决问题的建议。

编辑: 我发现这是线程的问题,所以解决方案可能是锁定 write/read.

好吧,一般在高并发环境下,这个问题真的很难解决,简单的Locking是行不通的(而且你不想使用table锁)。现在我使用来自 org.hibernate.annotations.SQLInsert 的 Hibernate @SQLInsert 注释,所以我的实体看起来像这样:

@SQLInsert(sql = "INSERT INTO my_entity_table(a, b, c) VALUES(?, ?, ?) ON DUPLICATE KEY UPDATE a=a;")
public class MyEntity implements Serializable {...}

当然会有问题,当您想向用户显示一些错误消息时,但在我的情况下它已经足够了。 据我所知,此 SQL 语句仅在 MySQL 中受支持,在其他 RDBMS 中,您应该使用不同的方法。