【问题标题】:Manage Hibernate and Activiti with Common TransactionManager使用 Common TransactionManager 管理 Hibernate 和 Activiti
【发布时间】:2017-11-23 21:40:33
【问题描述】:

我想为hibernate和activiti使用一个通用的事务管理器(JpaTransactionManager),但我不能!我已经为此阅读了所有互联网资源!听到的是一个简单的场景(甚至不使用休眠!!):

  1. 在任务中保存变量
  2. 在task#execution中保存变量
  3. 完成任务

场景实现(在带有@Transactional注解的spring bean方法中):

@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());
    }
}

很明显:如果taskService.complete抛出错误,整个事务应该回滚,所以所有保存的变量都应该回滚,下面的测试用例应该通过:

@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"));
}

但它失败了,变量被提交到数据库(不回滚)。

Spring 上下文(使用org.springframework.orm.jpa.JpaTransactionManager 作为事务管理器):

<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>

版本:

  • Activiti 版本:5.22.0
  • DB:h2(也在生产环境中使用 Oracle 进行了测试)

我的配置有什么问题?

附言

更新::

通过使用org.springframework.jdbc.datasource.DataSourceTransactionManager 而不是org.springframework.orm.jpa.JpaTransactionManager,测试用例通过了。但现在我无法持久化 JPA 实体。

【问题讨论】:

  • 投反对票原因??

标签: spring hibernate jpa activiti transactionmanager


【解决方案1】:

通过解决 MyBatis (JDBC) 和 Hibernate (JPA) 之间的冲突来解决问题:

jpaVendorAdapter 属性应该添加到entityManagerFactory bean:

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

所以entityManagerFactory 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="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </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>

更多详情见this question的回答。

【讨论】:

    猜你喜欢
    • 2013-02-15
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 2017-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多