1

I have implemented EntityListener in eclipseLink. My app is built using spring-boot , spring-data and eclipseLink. I have a requirement of inserting record in 2 table (Audit tables) when data in inserted in 1 table. I have got EntityManager in my Listener and everything seems to works normally. When I debug the code I can see that entities which I am going to save are having "id" generated from the sequence which is maintained at DB level. BUT when the transaction is committed I see only main table data but audit tables data is not getting committed. Here is the sample code :

@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
}

Listener code :

 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);
        }
    }

Nothing seems to be wrong with the code. BUT when I see in the set the sql logs to "FINEST" , I can see that insert queries are not being fired for audit tables. I have been dealing with this problem for more than 2 days and dont understand what exactly is wrong. Please help me.

rishi
  • 1,792
  • 5
  • 31
  • 63

1 Answers1

2

You are never calling flush on the EntityManager. I suspect something like the following is going on:

  1. You add your domain entities to the EntityManager, possibly through Spring Repositories.

  2. Something triggers a flush, possibly the transaction handling of Spring.

  3. Your domain entities get flushed.

  4. Your event listener gets triggered.

  5. You add audit entities to the EntityManager, but those never get flushed.

  6. The database connection gets a commit. Saving everything but your audit trail.

If this theory ist correct, which you should be able to verify through the logs and debugger, you can probably fix it, by adding a call to flush in your listener.

As you described in the comments this causes further problems, which happen because you are trying to do something which you are not supposed to be doing.

According to this article, the JPA spec does not allow usage of the entitymanager inside callback events.

In general, the lifecycle method of a portable application should not invoke EntityManager or Query operations, access other entity instances, or modify relationships within the same persistence context. A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.

So looks, like we are stuck here, so you probably should consider a completely different approach like EclipseLink History tables.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • 1
    Yes. Your understanding is correct that my audit entities are not getting flushed and I have verified it in sql logs. BUT I have already tried "flush". If I use flush I get "UniqueConstraintsViolation exception" because it flushes everything and as soon as the transaction gets committed by spring it again tries to save "MyTable" data which results in same entity getting persisted. – rishi Mar 06 '17 at 11:15