Skip to content
Advertisement

How can I batch the audit table inserts using the Hibernate Envers ValidityAuditStrategy

I’m using Hibernate envers for auditing, and most of my tables are performing batch inserts just fine. However, on one of my entities I have an audited collection, which seems like it doesnt want to batch.

MyEntity:

@Entity
@DynamicUpdate
@Indexed(index = "aj")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ElementGroup {
  ...      
@ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.DETACH, CascadeType.MERGE })
    @BatchSize(size = 30)
    @OrderBy("id ASC")
    @JoinTable(
            name = "element_groups",
            joinColumns = @JoinColumn(name = "group_id"),
            inverseJoinColumns = @JoinColumn(name = "member_id")
    )
    @Audited
    protected List<Element> members = new LinkedList<Element>();

(Not sure if this is important, Im using postgresql). In the logs I see 1000s of these statements in a loop

DEBUG 2021-11-07 15:28:56,673 [applicationInterfcePublishTaskExecuter-4::o.h.SQL.logStatement] [user:system] 
insert 
into
    nst_netobj_groups_aud
    (revtype, revend, rev, group_id, member_id) 
values
    (?, ?, ?, ?, ?)
DEBUG 2021-11-07 15:28:56,677 [applicationInterfcePublishTaskExecuter-4::o.h.SQL.logStatement] [user:system] 
    select
        nst_netobj0_.rev as rev1_137_,
        nst_netobj0_.group_id as group_id2_137_,
        nst_netobj0_.member_id as member_i3_137_,
        nst_netobj0_.revtype as revtype4_137_,
        nst_netobj0_.revend as revend5_137_ 
    from
        nst_netobj_groups_aud nst_netobj0_ 
    where
        nst_netobj0_.group_id=? 
        and nst_netobj0_.member_id=? 
        and (
            nst_netobj0_.revend is null
        ) for update
            of nst_netobj0_

Doing some debugging, I’ve understood that the select for update statement is causing the flush of the previous insert, not allowing them to batch. This line seems to be the reason:

        final List<Object> l = qb.toQuery( session ).setLockOptions( LockOptions.UPGRADE ).list();

hibernate-envers-5.4.27.Final-sources.jar!/org/hibernate/envers/strategy/internal/ValidityAuditStrategy.java:328

I see that setting flush mode to Manual/Commit doesnt seem to help. Any suggestions?

Full stack trace:

    logStatement:125, SqlStatementLogger (org.hibernate.engine.jdbc.spi)
prepareStatement:170, StatementPreparerImpl$StatementPreparationTemplate (org.hibernate.engine.jdbc.internal)
prepareQueryStatement:151, StatementPreparerImpl (org.hibernate.engine.jdbc.internal)
prepareQueryStatement:2104, Loader (org.hibernate.loader)
executeQueryStatement:2041, Loader (org.hibernate.loader)
executeQueryStatement:2019, Loader (org.hibernate.loader)
doQuery:948, Loader (org.hibernate.loader)
doQueryAndInitializeNonLazyCollections:349, Loader (org.hibernate.loader)
doList:2850, Loader (org.hibernate.loader)
doList:2832, Loader (org.hibernate.loader)
listIgnoreQueryCache:2664, Loader (org.hibernate.loader)
list:2659, Loader (org.hibernate.loader)
list:506, QueryLoader (org.hibernate.loader.hql)
list:400, QueryTranslatorImpl (org.hibernate.hql.internal.ast)
performList:219, HQLQueryPlan (org.hibernate.engine.query.spi)
list:1414, SessionImpl (org.hibernate.internal)
doList:1625, AbstractProducedQuery (org.hibernate.query.internal)
list:1593, AbstractProducedQuery (org.hibernate.query.internal)
performCollectionChange:328, ValidityAuditStrategy (org.hibernate.envers.strategy.internal)
performCollectionChange:76, AuditStrategy (org.hibernate.envers.strategy)
perform:87, PersistentCollectionChangeWorkUnit (org.hibernate.envers.internal.synchronization.work)
executeInSession:125, AuditProcess (org.hibernate.envers.internal.synchronization)
doBeforeTransactionCompletion:164, AuditProcess (org.hibernate.envers.internal.synchronization)
doBeforeTransactionCompletion:47, AuditProcessManager$1 (org.hibernate.envers.internal.synchronization)
beforeTransactionCompletion:954, ActionQueue$BeforeTransactionCompletionProcessQueue (org.hibernate.engine.spi)
beforeTransactionCompletion:525, ActionQueue (org.hibernate.engine.spi)
beforeTransactionCompletion:2381, SessionImpl (org.hibernate.internal)
beforeTransactionCompletion:447, JdbcCoordinatorImpl (org.hibernate.engine.jdbc.internal)
beforeCompletionCallback:183, JdbcResourceLocalTransactionCoordinatorImpl (org.hibernate.resource.transaction.backend.jdbc.internal)
access$300:40, JdbcResourceLocalTransactionCoordinatorImpl (org.hibernate.resource.transaction.backend.jdbc.internal)
commit:281, JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl (org.hibernate.resource.transaction.backend.jdbc.internal)
commit:101, TransactionImpl (org.hibernate.engine.transaction.internal)
doCommit:562, JpaTransactionManager (org.springframework.orm.jpa)
processCommit:743, AbstractPlatformTransactionManager (org.springframework.transaction.support)
commit:711, AbstractPlatformTransactionManager (org.springframework.transaction.support)
execute:152, TransactionTemplate (org.springframework.transaction.support)
lambda$publishApplicationInterfaceAsync$0:298, ApplicationInterfaceService (com.tufin.secureapp.service.interfaces)
run:-1, 16579879 (com.tufin.secureapp.service.interfaces.ApplicationInterfaceService$$Lambda$669)
runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
run:748, Thread (java.lang)

Advertisement

Answer

I checked it out, and here’s what I found:

  • Chris, who’s been doing most of Envers fixes during my time as a Hibernate dev, wrote this reply telling that there’s no workaround at the moment
  • there’s the HHH-14664 issue created for this problem, but no one provided a fix for it.

So, until someone fixes [HHH-14664], the only option would be to provide a CustomValidityAuditStrategy that extends the ValidityAuditStrategy and fixes the issue.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement