hibernatemulti-tenanthibernate-envers

Envers with Hibernate Multi Tenant


I have a project that i am migrating to use hibernate multitenancy feature. So far, i am injecting the EntityManager like this

@Inject
protected EntityManager em;

With a producer method that looks something like this

@Produces
@Default
@RequestScoped
public EntityManager create() {
 String principalName = principal.getName();
 String clientIdentifier = getClientIdentifier(principalName);
 MultiTenantResolver tenantResolver = (MultiTenantResolver) ((SessionFactoryImplementor) entityManagerFactory).getCurrentTenantIdentifierResolver();
 tenantResolver.setTenantIdentifier(clientIdentifier);
 EntityManager entityManager = entityManagerFactory.createEntityManager();
 logger.debug("=========== created entity manager " + entityManager);
 return entityManager;
}

(I am not posting the code of the multitenant implementation classes as i think it is not relevant but i could)

The creation of the EntityManager is working fine, the users are providing their credentials, starting a session and an EntityManager is being created, connected to the right database for each user / request

But when i try to perform a transaction that audits data (via envers with @Autited entities) the transaction cannot commit because of this exception

Caused by: org.hibernate.envers.exception.AuditException: Negative revision numbers are not allowed
    at org.hibernate@6.2.6.Final//org.hibernate.envers.internal.revisioninfo.DefaultRevisionInfoGenerator.saveRevisionData(DefaultRevisionInfoGenerator.java:64)
    at org.hibernate@6.2.6.Final//org.hibernate.envers.internal.synchronization.AuditProcess.getCurrentRevisionData(AuditProcess.java:138)
    at org.hibernate@6.2.6.Final//org.hibernate.envers.internal.synchronization.AuditProcess.executeInSession(AuditProcess.java:115)
    at org.hibernate@6.2.6.Final//org.hibernate.envers.internal.synchronization.AuditProcess.doBeforeTransactionCompletion(AuditProcess.java:175)
    at org.hibernate@6.2.6.Final//org.hibernate.envers.internal.synchronization.AuditProcessManager$1.doBeforeTransactionCompletion(AuditProcessManager.java:47)
    at org.hibernate@6.2.6.Final//org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:1010)
    at org.hibernate@6.2.6.Final//org.hibernate.engine.spi.ActionQueue.beforeTransactionCompletion(ActionQueue.java:548)
    at org.hibernate@6.2.6.Final//org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:1967)
    at org.hibernate@6.2.6.Final//org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:439)
    at org.hibernate@6.2.6.Final//org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl.beforeCompletion(JtaTransactionCoordinatorImpl.java:336)
    at org.hibernate@6.2.6.Final//org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:47)
    at org.hibernate@6.2.6.Final//org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:37)
    at org.jboss.as.transactions@29.0.1.Final//org.jboss.as.txn.service.internal.tsr.JCAOrderedLastSynchronizationList.beforeCompletion(JCAOrderedLastSynchronizationList.java:113)
    at org.wildfly.transaction.client@3.0.0.Final//org.wildfly.transaction.client.AbstractTransaction.performConsumer(AbstractTransaction.java:236)
    at org.wildfly.transaction.client@3.0.0.Final//org.wildfly.transaction.client.AbstractTransaction.performConsumer(AbstractTransaction.java:247)
    at org.wildfly.transaction.client@3.0.0.Final//org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization.beforeCompletion(AbstractTransaction.java:292)
    at org.jboss.jts//com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple.beforeCompletion(SynchronizationImple.java:76)
    at org.jboss.jts//com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.beforeCompletion(TwoPhaseCoordinator.java:360)
    at org.jboss.jts//com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:91)
    at org.jboss.jts//com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:162)
    at org.jboss.jts//com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1295)
    ... 125 more

I don't exactly know what can be happening, any pointers ???

Thanks a lot


Solution

  • It turns out that the problem was the sequence that i was using for the audit info table (the header?) for the audit data

    According to this article https://github.com/hibernate/hibernate-orm/blob/6.0/migration-guide.adoc#defaults-for-implicit-sequence-generators, the sequence has to comply with some expectations

    Once i created the sequence according to that expectations, envers is working fine

    This is the query i used:

    create sequence audit_info_seq start with 1 increment 1 cache 50;