我们在数据库事务中看到了奇怪的行为 - 它们不是原子行为。我们使用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。
有人能指出这是怎么发生的吗?
答案 0 :(得分:0)
您面临的主要问题是连接不可用。这种必须的例外导致事务的回滚。
捕获未处理的事务将改变事务的行为。第一个em.flush()
期间的例外也会删除您不想丢失的第一个em.persist(entity1)
。
因此,解决方案是在em.flush()
之前添加try
,以确保实体1的持久性得到保证或导致异常,这将导致整个事务的回滚。
我不推荐这种解决方案。
如果entity2
的持久性是可选的,那么通常您可以在额外的事务中执行此操作,这意味着系统将需要(在短时间内)额外的数据库连接。
如何创建额外的交易?在Ejb中,您使用REQUIRES_NEW注释方法。我不确定你在这里使用什么样的TransactionManagement,但我很确定应该有可能创建一种单独的事务(不要被嵌套事务混淆!!)。