非原子行为Eclipselink-DB交易一半承诺

时间:2017-09-30 16:04:14

标签: mysql jpa transactions eclipselink hikaricp

我们在数据库事务中看到了奇怪的行为 - 它们不是原子行为。我们使用MySQL 5.6.25 Innodb ,Eclipselink 2.5.2作为JPA提供程序,使用HikariCP 2.6.2作为连接池。

如果在entityManager.flush调用期间Eclipselink无法从池中获取连接,则会出现此问题。有一段时间,我们正在吞下这个例外,因为在最大努力的基础上进入特定的表 - 你可以说是一种审计模式。然而,这导致只有一部分交易承诺的情况,只有1,2或3个条目被保留。

可以肯定的是,这是事件的流程

    tx.begin();
    em.persist(entity1);
    try{
        em.persist(entity2);
        em.flush(); ---> this is where connection acquisition fails.
    } catch(Throwable tx){
     //do nothing, except log.
    }
    em.persist(entity3);
    em.flush();
    em.persist(entity4);
    em.flush();
    em.persist(entity5);
    em.flush();

    em.persist(entity6);
    tx.commit();

当连接获取在后来的刷新中的某个时刻再次失败时,我们看到事务一直提交到entity3,entity4,entity5。

有人能指出这是怎么发生的吗?

1 个答案:

答案 0 :(得分:0)

您面临的主要问题是连接不可用。这种必须的例外导致事务的回滚。 捕获未处理的事务将改变事务的行为。第一个em.flush()期间的例外也会删除您不想丢失的第一个em.persist(entity1)

因此,解决方案是在em.flush()之前添加try,以确保实体1的持久性得到保证或导致异常,这将导致整个事务的回滚。

我不推荐这种解决方案。

如果entity2的持久性是可选的,那么通常您可以在额外的事务中执行此操作,这意味着系统将需要(在短时间内)额外的数据库连接。

如何创建额外的交易?在Ejb中,您使用REQUIRES_NEW注释方法。我不确定你在这里使用什么样的TransactionManagement,但我很确定应该有可能创建一种单独的事务(不要被嵌套事务混淆!!)。