Spring JpaTransactionManager not saving Activiti entities to DB

1.8k views Asked by At

Nothing about Activiti is being saved to database. Application entities ARE being saved to database. Below, in order are, the spring file, persitence.xml file and the test case.

Using SQL Server profiler, I see a separate database transaction being started for the database interaction caused by Activiti and further I see that separate transaction being rolled back instead of being committed. Other application db interaction is happening on another transaction and this particular transaction is being committed.

  1. I thought, given my configurations, Activiti database interaction would happen on the same transaction as the rest of the application. I have gone through my configuration files and code numerous times and do not see anything wrong therein. Any ideas why a separate transaction is being started for the Activiti db interactions?
  2. Of course the previous item is the critical question. However, it would also be interesting to know why is that separate transaction being rolled back?

Spring file :

<context:annotation-config/>
<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="ActivitiTrialDataSource" class="org.apache.commons.dbcp.BasicDataSource" >
    <property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver" />
    <property name="url" value="jdbc:jtds:sqlserver://localhost:1433/ActivitiTrial" />
    <property name="username" value="ActivitiTrial" />
    <property name="password" value="ActivitiTrial" />
    <property name="defaultAutoCommit" value="false" />
    <property name="initialSize" value="5" />
</bean>


<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>


<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="ActivitiTrialDataSource" />
    <property name="persistenceUnitName" value="ActivitiTrial"/>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>



<!-- Activiti -->
<bean id="activitiDataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    <property name="targetDataSource" ref="ActivitiTrialDataSource" />
</bean>

<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
    <property name="databaseType" value="mssql" />
    <property name="dataSource" ref="activitiDataSource" />
    <property name="transactionsExternallyManaged" value="true" />
    <property name="transactionManager" ref="transactionManager" />
    <property name="databaseSchemaUpdate" value="false" />
    <property name="history" value="audit" />
    <property name="jobExecutorActivate" value="false" />
</bean>

<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
    <property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>

<bean id="activitiRepositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
<bean id="activitiRuntimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
<bean id="activitiTaskService" factory-bean="processEngine" factory-method="getTaskService" />
<bean id="activitiHistoryService" factory-bean="processEngine" factory-method="getHistoryService" />
<bean id="activitiManagementService" factory-bean="processEngine" factory-method="getManagementService" />

persitence.xml file:

<persistence-unit name="ActivitiTrial">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <properties>
        <property name="hibernate.archive.autodetection" value="hbm,class"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
        <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
        <property name="hibernate.hbm2ddl.auto" value="none"/>
        <property name="hibernate.show_sql" value="false"/>
        <property name="hibernate.ejb.metamodel.generation" value="disabled"/>
    </properties>
</persistence-unit>

Test case:

@RunWith(SpringJUnit4ClassRunner.class)
@TransactionConfiguration(defaultRollback=false)
@ContextConfiguration({"classpath:/springApplicationContext.xml"})
public class TrialTest {
    @Autowired
    RepositoryService activitiRepositoryService;

    @Autowired
    RuntimeService activitiRuntimeService;

    @Autowired
    TaskService activitiTaskService;


    @PersistenceContext(unitName="ActivitiTrial")
    EntityManager entityManager;



    @Test
    @Transactional
    public void trialTest() throws Exception {
        long entryMilliseconds = new Date().getTime();


        activitiRepositoryService.createDeployment().addClasspathResource("process-definitions/neville.bpmn20.xml").deploy();


        ApplicationEntity applicationEntity1 = new ApplicationEntity();
        applicationEntity1.name = "App entity 1";
        applicationEntity1.createDate = new Date();
        Session hibernateSessionBeforeActiviti = ((Session) entityManager.getDelegate());
        entityManager.persist(applicationEntity1);
        entityManager.flush();


        Map<String, Object> processVariables = new HashMap<String, Object>();
        processVariables.put("ApplicationEntityID", applicationEntity1.id);
        ProcessInstance processInstance = activitiRuntimeService.startProcessInstanceByKey("neville", processVariables);
        String processInstanceId = processInstance.getId();
        Task userTask = activitiTaskService.createTaskQuery().processInstanceId(processInstanceId).list().get(0);


        ApplicationEntity applicationEntity2 = new ApplicationEntity();
        applicationEntity2.name = "App entity 2";
        applicationEntity2.createDate = new Date();
        Session hibernateSessionAfterActiviti = ((Session) entityManager.getDelegate());
        entityManager.persist(applicationEntity2);
        entityManager.flush();


        System.out.println("Leaving trialTest() in : " + (new Date().getTime() - entryMilliseconds) + " milliseconds.");
    }
}
2

There are 2 answers

0
Arya On

I've solved this problem by resolving conflict between MyBatis (JDBC) and Hibernate (JPA):

You should add jpaVendorAdapter property to entityManagerFactory bean:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="ActivitiTrialDataSource" />
    <property name="persistenceUnitName" value="ActivitiTrial"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
</bean>

For more details see answer of this question.

0
VB_ On

I've already waste a lot of time trying to pass common transaction manager to Spring and Activiti - and no result. No mean of full answer to your question, but I hope it will save you some time

Activiti forum:

Demo:

These repos illustrate that Activiti don't accept jpa/hibernate transactions:

You also can see demo https://github.com/Activiti/Activiti (Activiti + Spring + Bitronix) it may help (I have no time to check it yet).

P.S.

As an alternative to common transaction I see compensation events.