JPA批处理插入导致ConstraintViolationException

时间:2015-05-05 15:10:30

标签: java hibernate jpa ejb

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

首先,我有MyEntity类与@Id和几个独特的字段。 我有@Stateless MyEntityRepository类和find()方法,只需通过调用EntityManager get()方法返回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);
    }
}

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

@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()方法抛出异常。

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

编辑: 我发现这是一个线程问题,因此解决方案可能是锁定写/读。

1 个答案:

答案 0 :(得分:0)

好吧,通常在高并发环境中,解决这个问题真的很难,只是锁定不起作用(你不想使用表锁)。现在我使用来自@SQLInsert的Hibernate org.hibernate.annotations.SQLInsert注释,所以我的实体看起来像这样:

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

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