Transaction management with Spring in Activiti

You can make sure that Activiti uses the transaction manager defined in Spring using the “transactionManagement” property on the SpringProcessEngineConfiguration class.

This works but behaves different from how Hibernate/JPA behave.

When you explicitly create your transaction boundaries (using TransactionTemplate or @Transactional annotations), these are simple used as expected.

However if you do not define the transaction boundaries, Hibernate/JPA will throw an exception indication that a transaction needs to be active while Activiti will simply create a transaction, more or less working in autocommit mode.

You can assure that Activiti has similar behaviour as Hibernate/JPA by using a custom SpringProcessEngineConfiguration class. Unfortunately, this does not work in all cases. When you use the jobExecutor (so jobExecutorActive needs to be false). You also need to assure that the conversion does not occur during auto deploy of resources.

public class MySpringProcessEngineConfiguration extends SpringProcessEngineConfiguration {
 
    private DcSpringTransactionInterceptor txInterceptor;
 
    @Override
    protected CommandInterceptor createTransactionInterceptor() {
        if (transactionManager == null) {
            throw new ActivitiException("transactionManager is required property for SpringProcessEngineConfiguration, use "
                    + StandaloneProcessEngineConfiguration.class.getName() + " otherwise");
        }
 
        txInterceptor = new DcSpringTransactionInterceptor(transactionManager);
        return txInterceptor;
    }
 
    @Override
    public ProcessEngine buildProcessEngine() {
        if (null != txInterceptor) {
            txInterceptor.setConvertRequiredToMandatory(false);
        }
        ProcessEngine processEngine = super.buildProcessEngine();
        ProcessEngines.setInitialized(true);
        autoDeployResources(processEngine);
        if (null != txInterceptor) {
            txInterceptor.setConvertRequiredToMandatory(true);
        }
        return processEngine;
    }
 
}

The actual work is done in the MySpringTransactionInterceptor which converts REQUIRED transaction propagation to MANDATORY.

@Slf4j
class MySpringTransactionInterceptor extends SpringTransactionInterceptor {
 
    @Setter
    private boolean convertRequiredToMandatory;
 
    /**
     * Constructor.
     *
     * @param transactionManager transaction manager
     */
    DcSpringTransactionInterceptor(PlatformTransactionManager transactionManager) {
        super(transactionManager);
    }
 
    @Override
    public <T> T execute(final CommandConfig config, final Command<T> command) {
        log.debug("Running command with propagation {}", config.getTransactionPropagation());
 
        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
        transactionTemplate.setPropagationBehavior(getPropagation(config));
 
        return transactionTemplate.execute((status) -> next.execute(config, command));
    }
 
    private int getPropagation(CommandConfig config) {
        switch (config.getTransactionPropagation()) {
            case NOT_SUPPORTED:
                return TransactionTemplate.PROPAGATION_NOT_SUPPORTED;
            case REQUIRED:
                if (convertRequiredToMandatory) {
                    return TransactionTemplate.PROPAGATION_MANDATORY; // omgezet naar mandatory, tx handling moet expliciet gebeuren
                } else {
                    return TransactionTemplate.PROPAGATION_REQUIRED;
                }
            case REQUIRES_NEW:
                return TransactionTemplate.PROPAGATION_REQUIRES_NEW;
            default:
                throw new ActivitiIllegalArgumentException("Unsupported transaction propagation: " + config.getTransactionPropagation());
        }
    }
 
}

Leave a Reply

Your email address will not be published. Required fields are marked *

question razz sad evil exclaim smile redface biggrin surprised eek confused cool lol mad twisted rolleyes wink idea arrow neutral cry mrgreen

*