cancel
Showing results for 
Search instead for 
Did you mean: 

How do two service method TaskService in a one transaction?

kolmogorov_dikm
Champ in-the-making
Champ in-the-making
I wrote a simple test that calls a service that creates a task and stores variables. Between conservation task and variables raises an exception, the task saved, and the variables do not. What do I need to call these methods executed in a single transaction?

junit test

        @Test
   @Rollback(value = false)
   public void testTaskWorkFlowServiceTran() throws Exception {

      Map<String, Object> vars = new HashMap<String, Object>();
      vars.put("var1", "value1");

      TaskEntity task = new TaskEntity();
      task.setName("name");
      task.setDescription("desc");
      task.setPriority(60);
      task.setDueDate(Calendar.getInstance().getTime());
      task.setOwner("owner");
      task.setAssignee("assignee");
      taskTestService.createTask(task, vars);
   }

spring service

@Service
@Transactional
public class TaskTestService {

   @Autowired
   private TaskService taskService;
   
   public void createTask(TaskEntity taskEntity, Map<String, Object> vars) throws Exception {
      Task task = taskService.newTask();
      task.setName(taskEntity.getName());
      task.setDescription(taskEntity.getDescription());
      task.setPriority(taskEntity.getPriority());
      task.setDueDate(taskEntity.getDueDate());
      task.setOwner(taskEntity.getOwner());
      task.setAssignee(taskEntity.getAssignee());
      taskService.saveTask(task);
      
      if (vars != null) {
         throw new Exception("boom!");
      } else {
         taskService.setVariables(task.getId(), vars);
      }
   }
}

application context

       <context:component-scan base-package="ru.nti.siu.bpm.test" />
   
   <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
      <property name="databaseType" value="postgres" />
      <property name="dataSource" ref="myDataSource" />
      <property name="transactionManager" ref="myTransactionManager" />
      <property name="databaseSchemaUpdate" value="false" />
      <property name="history" value="full" />
      <property name="jobExecutorActivate" value="false" />
      <property name="idGenerator">
         <bean class="org.activiti.engine.impl.persistence.StrongUuidGenerator" />
      </property>
   </bean>

   <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
      <property name="processEngineConfiguration" ref="processEngineConfiguration" />
   </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="myTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="myDataSource" />
     </bean>
       
    <bean id="myDataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
       <property name="driverClass" value="org.postgresql.Driver" />
       <property name="url" value="jdbc:postgresql://192.168.1.1/mydatabase" />
       <property name="username" value="postgres" />
       <property name="password" value="postgres" />
     </bean>
7 REPLIES 7

frederikherema1
Star Contributor
Star Contributor
Do you explicitly state transactions should be annotation-based?


<tx:annotation-driven/>

kolmogorov_dikm
Champ in-the-making
Champ in-the-making
I changed the appication context to this, but as usual methods in different transactions.


<context:component-scan base-package="ru.nti.siu.bpm.test" />

<bean id="myDataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
  <property name="driverClass" value="org.postgresql.Driver" />
  <property name="url" value="jdbcSmiley Tongueostgresql://192.168.1.1/mydatabase" />
  <property name="username" value="postgres" />
  <property name="password" value="postgres" />
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="myDataSource" />
</bean>

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


<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
  <property name="databaseType" value="postgres" />
  <property name="dataSource" ref="myDataSource" />
  <property name="transactionManager" ref="transactionManager" />
  <property name="databaseSchemaUpdate" value="false" />
  <property name="history" value="full" />
  <property name="jobExecutorActivate" value="false" />
  <property name="idGenerator">
   <bean class="org.activiti.engine.impl.persistence.StrongUuidGenerator" />
  </property>
</bean>

<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
  <property name="processEngineConfiguration" ref="processEngineConfiguration" />
</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" />

frederikherema1
Star Contributor
Star Contributor
When using the spring process engine configuration, the datasource is wrapped (if not already of this type) in a TransactionAwareDataSourceProxy. This makes sure all connections requested from activiti are 'aware' of the underlying spring-transactions and therefore won't do an actual 'commit' when the connection is committed. On top of that, the "transactionsExternallyManaged = true;" property is set, so the transaction-interceptors in activiti won't kick in and assume the underlying platform will manage transaction demarcation and committing.

The only time activiti won't participate in an already running transaction (and uses REQUIRES_NEW) is when the ID-generator aquires a new block, but this is independent of any running transactions.

I'm not really sure what the issue is with your setup, it seems fine to me. Can you perhaps create a simple unit-test based on the template you can find in the sticky in this forum and share it?

kolmogorov_dikm
Champ in-the-making
Champ in-the-making
Sorry for the late reply, posted the draft on DropBox.

https://www.dropbox.com/s/bzinnmgm26g0loo/test.rar

udoderk
Champ in-the-making
Champ in-the-making
Sorry for the late reply, posted the draft on DropBox.


hi,
are you no more troubles with that problem solution? Are exceptions thrown or not?
https://www.dropbox.com/s/bzinnmgm26g0loo/test.rar
package ru.dikma;

import java.util.Map;

import org.activiti.engine.TaskService;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("TestTaskService")
public class TestTaskService {

@Autowired
private TaskService taskService;

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createTask(TaskEntity taskEntity, Map<String, Object> vars)
   throws Exception {
  Task task = taskService.newTask();
  task.setName(taskEntity.getName());
  task.setDescription(taskEntity.getDescription());
  task.setPriority(taskEntity.getPriority());
  task.setDueDate(taskEntity.getDueDate());
  task.setOwner(taskEntity.getOwner());
  task.setAssignee(taskEntity.getAssignee());
  taskService.saveTask(task);

  if (vars != null) {
   throw new Exception("boom!");
  } else {
   taskService.setVariables(task.getId(), vars);
  }
}
}

kolmogorov_dikm
Champ in-the-making
Champ in-the-making
You do not understand my question, it is expected that if between a call to save the task and save the variables exception occurs then the problem will not be saved, but it is not, although the method is declared as transactional. Check it out, they are two different transactions. How to configure the service, these two methods were in the same transaction?

udoderk
Champ in-the-making
Champ in-the-making
You do not understand my question, it is expected that if between a call to save the task and save the variables exception occurs then the problem will not be saved, but it is not, although the method is declared as transactional. Check it out, they are two different transactions. How to configure the service, these two methods were in the same transaction?
i well understand your problem, in your case is simpler to avoid exception throwing between save of task and "save" the variables :twisted: (i assume, that mybatis + own activiti implementation would be root of problem)

P.S In your test only "setter" method was called for variables after save operation for the created task. Look at
org.activiti.engine.impl.cmd.SetTaskVariablesCmd
org.activiti.engine.impl.persistence.entity.TaskEntity
org.activiti.engine.impl.persistence.entity.VariableScopeImpl.java
The call of this method not make persistent the variables.

P.P.S Your Test has no methods, that test, wether task were saved correctly or not.
P.P.P.S Your Test has no methods, that test, wether variables were saved or not.