2017-06-21 1 views
1

Je veux utiliser un gestionnaire de transactions commun() pour Hibernate et activiti, mais je ne peux pas! Et j'ai lu toutes les ressources internet pour ça! Entendre est un scénario simple (qui ne même pas mise en veille prolongée !! utiliser):Gérer Hibernate et Activiti avec Common TransactionManager

  1. Enregistrer les variables dans la tâche
  2. variables Enregistrer dans la tâche # exécution
  3. tâche complète

mise en œuvre du scénario (en une méthode de haricot de printemps avec @Transactional annotation):

@Component 
public class TaskManager { 

    @Autowired TaskService taskService; 
    @Autowired RuntimeService runtimeService; 

    @Transactional 
    public void completeTask(CompleteTaskRequest request) { 
     Task task = taskService.createTaskQuery().taskId(request.getTaskId()).singleResult(); 
     if (task == null) { 
      throw new ActivitiObjectNotFoundException("No task found"); 
     } 
     taskService.setVariableLocal(task.getId(), "actionDisplayUrl", request.getActionDisplayUrl()); 
     taskService.setVariableLocal(task.getId(), "actionSummaryUrl", request.getActionSummaryUrl()); 
     runtimeService.setVariableLocal(task.getExecutionId(), "prevTaskId", task.getId()); 
     taskService.complete(task.getId()); 
    } 
} 

Il est évident: si taskService.complete lancers francs erreur, toute l'opération devrait être rollbacked, de sorte que toutes les variables enregistrées doivent être rollbacked, et le cas de test ci-dessous devrait être adopté:

@Test 
@Deployment(resources = "org.activiti.test/CompleteTaskTest.bpmn20.xml") 
public void testCompleteTaskWithError() { 
    Map<String, Object> processVars = new HashMap<>(); 
    processVars.put("error", true); // Causes throwing error in ScriptTaskListener 
    runtimeService.startProcessInstanceByKey("CompleteTaskTest", processVars); 
    Task task = taskService.createTaskQuery().taskName("Task 1").singleResult(); 

    CompleteTaskRequest req = new CompleteTaskRequest(); 
    req.setTaskId(task.getId()); 
    req.setActionDisplayUrl("/actions/1234"); 
    req.setActionSummaryUrl("/actions/1234/summary"); 
    try { 
     taskManager.completeTask(req); 
     fail("An error expected!"); 
    } catch(Exception e) { 
    } 

    // Check variables rollback 
    assertNull(taskService.getVariableLocal(task.getId(),"actionSummaryUrl")); 
    assertNull(taskService.getVariableLocal(task.getId(),"actionDisplayUrl")); 
    assertNull(runtimeService.getVariableLocal(task.getExecutionId(), "prevTaskId")); 
} 

Mais il échoue, les variables sont engagés à DB (non rollbacked).

contexte de printemps (avec org.springframework.orm.jpa.JpaTransactionManager comme gestionnaire de transactions):

<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> 
    <property name="dataSource" ref="dataSource" /> 
    <property name="transactionManager" ref="transactionManager" /> 
    <property name="idGenerator" ref="idGenerator"/> 
    <property name="databaseSchemaUpdate" value="true" /> 
    <property name="jpaEntityManagerFactory" ref="entityManagerFactory" /> 
    <property name="jpaHandleTransaction" value="true" /> 
    <property name="jpaCloseEntityManager" value="true" /> 
    <property name="beans" ref="processEngineBeans" /> 
    <property name="jobExecutorActivate" value="false" /> 
    <property name="asyncExecutorEnabled" value="true" /> 
    <property name="asyncExecutorActivate" value="true" /> 
</bean> 

<aop:config proxy-target-class="true" /> 
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> 

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

<bean id="processEngineBeans" class="java.util.HashMap"> 
    <constructor-arg index="0" type="java.util.Map"> 
     <map> 
     </map> 
    </constructor-arg> 
</bean> 

<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" /> 
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" /> 
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" /> 
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" /> 
<bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" /> 
<bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService" /> 
<bean id="formService" factory-bean="processEngine" factory-method="getFormService" /> 
<bean id="idGenerator" class="org.activiti.engine.impl.persistence.StrongUuidGenerator" /> 

<bean id="activitiRule" class="org.activiti.engine.test.ActivitiRule"> 
    <property name="processEngine" ref="processEngine" /> 
</bean> 


<bean id="persistenceUnitManager" 
    class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"> 
    <property name="packagesToScan" value="org.activiti.test" /> 
    <property name="defaultDataSource" ref="dataSource" /> 
</bean> 

<bean id="entityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="persistenceUnitManager" ref="persistenceUnitManager" /> 
    <property name="persistenceProvider"> 
     <bean class="org.hibernate.jpa.HibernatePersistenceProvider" /> 
    </property> 
    <property name="jpaProperties"> 
     <props> 
     <prop key="hibernate.dialect_resolvers">org.hibernate.engine.jdbc.dialect.internal.DialectResolverSet</prop> 
     <prop key="hibernate.hbm2ddl.auto">create</prop> 
     <prop key="hibernate.cache.use_second_level_cache">false</prop> 
     <prop key="hibernate.cache.use_query_cache">false</prop> 
     <prop key="hibernate.show_sql">true</prop> 
     </props> 
    </property> 
</bean> 

<bean id="dataSource" 
    class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> 
    <property name="driverClass" value="org.h2.Driver" /> 
    <property name="url" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" /> 
    <property name="username" value="sa" /> 
    <property name="password" value="" /> 
</bean> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory"/> 
</bean> 
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> 

<!-- bean post-processor for JPA annotations --> 
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> 

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" > 
    <property name="proxyTargetClass" value="true" /> 
</bean> 

Versions:

  • Version Activiti: 5.22.0
  • DB: h2 (également testé avec Oracle dans la production)

Quel est le problème avec mes configurations?

P.S.

  • Le projet de test est chargé here.
  • J'ai également posé cette question dans alfresco forum.

MISE À JOUR ::

En utilisant org.springframework.jdbc.datasource.DataSourceTransactionManager au lieu de org.springframework.orm.jpa.JpaTransactionManager le cas de test passé. Mais maintenant je ne peux pas persister les entités JPA.

+0

La raison du vote négatif? – united

Répondre

0

Le problème est résolu par la résolution des conflits entre mybatis (JDBC) et Hibernate (JPA):

jpaVendorAdapter propriété doit être ajouté à entityManagerFactory haricot:

<property name="jpaVendorAdapter"> 
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> 
</property> 

Alors entityManagerFactory haricot devrait ressembler à ceci: Pour plus de détails, voir la réponse this question.