cancel
Showing results for 
Search instead for 
Did you mean: 

With Spring integration, MyBatis closed db connection early

xml2008
Champ in-the-making
Champ in-the-making
Hi,

I am trying to embed activiti (5.0rc1) engine in my web app with spring integration,
and doing something like following code:

public class UserBean {

  /** injected by Spring */
  private RuntimeService runtimeService;

  @Transactional
  public void hello() {
    // here you can do transactional stuff in your domain model
    // and it will be combined in the same transaction as
    // the startProcessInstanceByKey to the Activiti RuntimeService
    runtimeService.startProcessInstanceByKey("helloProcess");
  }
 
  public void setRuntimeService(RuntimeService runtimeService) {
    this.runtimeService = runtimeService;
  }
}

but MyBatis ManagedTransaction will always close the db connection before the Spring Transaction commits.


public class ManagedTransactionFactory implements TransactionFactory {

  private boolean closeConnection = true;

  public void setProperties(Properties props) {
    if (props != null) {
      String closeConnectionProperty = props.getProperty("closeConnection");
      if (closeConnectionProperty != null) {
        closeConnection = Boolean.valueOf(closeConnectionProperty);
      }
    }
  }

  public Transaction newTransaction(Connection conn, boolean autoCommit) {
    // Silently ignores autocommit, as managed transactions are entirely
    // controlled by an external manager.  It's silently ignored so that
    // code remains portable between managed and unmanaged configurations.
    return new ManagedTransaction(conn, closeConnection);
  }
}

DbSqlSessionFactory:


public void configurationCompleted(ProcessEngineConfiguration processEngineConfiguration) {
    this.databaseType = processEngineConfiguration.getDatabaseType();
    this.idGenerator = processEngineConfiguration.getIdGenerator();
    this.statementMappings = databaseSpecificStatements.get(processEngineConfiguration.getDatabaseType());

    DataSource dataSource = processEngineConfiguration.getDataSource();
    if (dataSource==null) { // standalone usage
      dataSource = createPooledDatasource(processEngineConfiguration);
    }
   
    TransactionFactory transactionFactory = null;
    if (processEngineConfiguration.isTransactionsExternallyManaged()) {
      transactionFactory = new ManagedTransactionFactory();
    } else {
      transactionFactory = new JdbcTransactionFactory();
    }
   
    this.sqlSessionFactory = createSessionFactory(dataSource, transactionFactory);
  }

Do I miss something to configure correctly?
7 REPLIES 7

jbarrez
Star Contributor
Star Contributor
Probably your datasource is not correctly specified. Could you give your spring config ?

xml2008
Champ in-the-making
Champ in-the-making
Thanks for your attention.

My dataSource is just defined as following:


<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
        <property name="driverClassName">
            <value>${database.driver_class}</value>
        </property>
        <property name="url">
            <value>${database.url}</value>
        </property>
        <property name="username">
            <value>${database.username}</value>
        </property>
        <property name="password">
            <value>${database.password}</value>
        </property>
        <property name="defaultAutoCommit">
            <value>false</value>
        </property>
        <property name="maxActive">
            <value>${database.maxActive}</value>
        </property>
  <!–
        <property name="validationQuery">
            <value>select * from Test</value>
        </property>–>
    </bean>

After I debug through the code, I found that :

when a new SqlSession is created by DefaultSqlSessionFactory.openSession method:

public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

a new db connection is obtained from datasource instead of spring's managed thread local connection.

But when MyBatis's ManagedTransaction.commit method is invoked:

public void commit() throws SQLException {
    // Does nothing
}

previous connection is closed without commitment, so nothing is saved to database at all.

Is that  the desired behavior?

tombaeyens
Champ in-the-making
Champ in-the-making
Did you use the ProcessEngineFactoryBean to build the process engine?

If that is the case and you still experience a problem with tomorrow's 5.0 release, file a jira for this with the full spring configuration file.

jbarrez
Star Contributor
Star Contributor
You need to wrap the datasource in a TransactionalAwareDatasource, that should fix your problem (check the Spring example configs that are shipped with Activiti).

xml2008
Champ in-the-making
Champ in-the-making
The problem is solved after I upgrated to 5.0GA. Thanks for your help.

dli
Champ in-the-making
Champ in-the-making
I do have this problem when i using acticiti5.17 with spring now,i don't know how to do.

look at my spring config:

<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
     <property name="dataSource" ref="mysql" />
     <property name="transactionManager" ref="transactionManager" />
     <property name="databaseSchemaUpdate" value="false" />
     <property name="jobExecutorActivate" value="false" />
     <property name="asyncExecutorEnabled" value="true" />
     <property name="asyncExecutorActivate" value="false" />
  </bean>

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

jbarrez
Star Contributor
Star Contributor
Your xml is missing, you have to use code tags to post xml.