我已经在eclipselink中实现了EntityListener。我的应用是使用Spring-Boot,Spring-Data和Eclipselink构建的。当数据插入1个表中时,我需要将记录插入2个表(审核表)。我的听众中有EntityManager,一切似乎正常起作用。当我调试代码时,我可以看到要保存的实体是从DB级别维护的序列中生成的" ID"。但是,当交易订立时,我只会看到主表数据,但是审核表数据并未提交。这是示例代码:
@Entity
@Table(name="MyTable")
@EntityListeners(MyTableListener.class)
public class MyTable implements Serializable{
private static final long serialVersionUID = -5087505622449571373L;
private Long id;
// Rest of the fields
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="MASTER_SEQ")
@SequenceGenerator(name="MASTER_SEQ",sequenceName="MASTER_SEQ",allocationSize=1)
public Long getId() {
return id;
}
// Getters/Setters
}
听众代码:
public class MyTableListener extends DescriptorEventAdapter {
@Override
public void postInsert(DescriptorEvent event) {
MyTable msg = (MyTable)((InsertObjectQuery) event.getQuery()).getObject();
EntityManager em = BeanUtil.getBean(EntityManager.class);
MyAudit statusAudit = new MyAudit();
statusAudit.setNewVal("NEW");
statusAudit.setOldval(null);
statusAudit.setTargetColumnName(targetColumn);
statusAudit.setTargetRecordId(msg.getId());
em.persist(statusAudit);
}
}
代码似乎没有错。但是,当我在集合中看到SQL日志"最好"时,我可以看到插入查询没有被触发以供审计表触发。我已经处理了这个问题已有2天以上的时间,并且不了解到底出了什么问题。请帮助我。
您从不在EntityManager
上调用flush
。我怀疑以下事情正在进行:
-
您可能通过春季存储库将您的域实体添加到EntityManager。
-
某些东西触发了潮流,可能是弹簧的交易处理。
-
您的域实体被冲洗了。
-
您的事件侦听器被触发。
-
您将审计实体添加到EntityManager,但这些实体永远不会被冲洗。
-
数据库连接获取提交。保存除了您的审核之路以外的所有内容。
如果此理论正确,您应该能够通过日志和调试器验证,您可以通过在侦听器中添加flush
的呼叫来修复它。
正如您在评论中所描述的那样,这会导致进一步的问题,这是因为您正在尝试做不应该做的事情。
根据本文,JPA规格不允许在回调事件中使用EntityManager。
通常,便携式应用程序的生命周期方法不应调用EntityManager或查询操作,访问其他实体实例,或在相同的持久性上下文中修改关系。生命周期回调方法可以修改调用其所在实体的非关系状态。
看起来,就像我们被困在这里一样,因此您可能应该考虑一种完全不同的方法,例如Eclipselink历史表。