一个MySql实例自动创建多个Activiti数据库问题

一次使用SSH和Activiti6开发的项目中,在服务器启动的时候就报错:

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.sql.SQLSyntaxErrorException: Table 'activiti.act_ge_property' doesn't exist
### The error may exist in org/activiti/db/mapping/entity/Property.xml
### The error may involve org.activiti.engine.impl.persistence.entity.PropertyEntityImpl.selectProperty-Inline
### The error occurred while setting parameters
### SQL: select * from ACT_GE_PROPERTY where NAME_ = ?

### Cause: java.sql.SQLSyntaxErrorException: Table 'activiti.act_ge_property' doesn't exist

查找表不存在?Activiti没有自动建表?

可配置文件确实将databaseSchemaUpdate属性设置为了true,这意味着activiti会执行无表创建,有表更新的策略

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

</bean>

但执行显示并没有起效。网上也没有靠谱的结果。。

只能自己查看源码。databaseSchemaUpdate设为true的时候,引擎会根据该值执行不同的策略,

在类org.activiti.engine.impl.db.DbSqlSession中,有这样一个方法:

public void performSchemaOperationsProcessEngineBuild() {
    String databaseSchemaUpdate = Context.getProcessEngineConfiguration().getDatabaseSchemaUpdate();
    log.debug("Executing performSchemaOperationsProcessEngineBuild with setting " + databaseSchemaUpdate);
    if (ProcessEngineConfigurationImpl.DB_SCHEMA_UPDATE_DROP_CREATE.equals(databaseSchemaUpdate)) {
      try {
        dbSchemaDrop();
      } catch (RuntimeException e) {
        // ignore
      }
    }
    if (org.activiti.engine.ProcessEngineConfiguration.DB_SCHEMA_UPDATE_CREATE_DROP.equals(databaseSchemaUpdate)
        || ProcessEngineConfigurationImpl.DB_SCHEMA_UPDATE_DROP_CREATE.equals(databaseSchemaUpdate) || ProcessEngineConfigurationImpl.DB_SCHEMA_UPDATE_CREATE.equals(databaseSchemaUpdate)) {
      dbSchemaCreate();

    } else if (org.activiti.engine.ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE.equals(databaseSchemaUpdate)) {
      dbSchemaCheckVersion();

    } else if (ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE.equals(databaseSchemaUpdate)) {
      dbSchemaUpdate();
    }
  }

它会根据databaseSchemaUpdate的值执行对应的方法,设为true则执行:

dbSchemaUpdate();

该方法中首先会判断引擎的表是否已存在了,存在执行更新逻辑,不存在执行创建逻辑

public String dbSchemaUpdate() {

    String feedback = null;
    boolean isUpgradeNeeded = false;
    int matchingVersionIndex = -1;

    if (isEngineTablePresent()) {
        PropertyEntity dbVersionProperty = selectById(PropertyEntity.class, "schema.version");
        String dbVersion = dbVersionProperty.getValue();
        ......
    }else {
      dbSchemaCreateEngine();
    }

问题就在这里,判断存在的时候会查询act_ge_property表中的

schema.version

字段,但这个时候你的数据库中是没有自动创建activiti的任何表的,所以会报出上面的异常。

那为什么

isEngineTablePresent()

方法会判断为true呢?

public boolean isEngineTablePresent() {
    return isTablePresent("ACT_RU_EXECUTION");通过判断表ACT_RU_EXECUTION是否存在
  }
public boolean isTablePresent(String tableName) {
    // ACT-1610: in case the prefix IS the schema itself, we don't add the
    // prefix, since the check is already aware of the schema
    if (!dbSqlSessionFactory.isTablePrefixIsSchema()) {
      tableName = prependDatabaseTablePrefix(tableName);
    }

    Connection connection = null;
    try {
      connection = sqlSession.getConnection();
      DatabaseMetaData databaseMetaData = connection.getMetaData();
      ResultSet tables = null;

      String catalog = this.connectionMetadataDefaultCatalog;
      if (dbSqlSessionFactory.getDatabaseCatalog() != null && dbSqlSessionFactory.getDatabaseCatalog().length() > 0) {
        catalog = dbSqlSessionFactory.getDatabaseCatalog();
      }

      String schema = this.connectionMetadataDefaultSchema;
      if (dbSqlSessionFactory.getDatabaseSchema() != null && dbSqlSessionFactory.getDatabaseSchema().length() > 0) {
        schema = dbSqlSessionFactory.getDatabaseSchema();
      }

      String databaseType = dbSqlSessionFactory.getDatabaseType();

      if ("postgres".equals(databaseType)) {
        tableName = tableName.toLowerCase();
      } 
      
      if (schema != null && "oracle".equals(databaseType)) {
        schema = schema.toUpperCase();
      }
      
      if (catalog != null && catalog.length() == 0) {
        catalog = null;
      }

      try {
        tables = databaseMetaData.getTables(catalog, schema, tableName, JDBC_METADATA_TABLE_TYPES);
        return tables.next();
      } finally {
        try {
          tables.close();
        } catch (Exception e) {
          log.error("Error closing meta data tables", e);
        }
      }

    } catch (Exception e) {
      throw new ActivitiException("couldn't check if tables are already present using metadata: " + e.getMessage(), e);
    }
  }

再以下的代码就是c3p0和mysql驱动那的了,我找了很久也没完全理清,而且maven帮我下的c3p0的源码和项目用的还不一样(为什么?。。),限于时间就没继续了,这里也不贴出来了。

最终方法判断为true的原因其实就是判断表

ACT_RU_EXECUTION

是否存在的时候找到了之前另一个项目的activiti数据库中的表,因而报错,把那个数据库删了,就运行通过了。有兴趣的同学可以自己看下后面执行的代码,应该是有一个快速判断数据库中某个表是否存在的方法。

上面配置文件中我加了一个scheme属性

<property name="databaseSchema" value="roomRent" />

值是本项目存放activiti数据表的数据库名(异常信息中是为了再现该问题用另一个项目做的测试,所以两个数据库不一样),本意是期待spring能够像注入其它属性一样把该属性也注入进activiti的配置类中,然后查询数据表是否存在的时候加上scheme约束,但调试的时候发现这个值没注入进去。并且正常情况下加入这个属性c3p0那边会报错,所以还是得去掉。

history和id的表第一次启动项目的时候并没有创建,它们会在之后比如第二次启动项目或者用到的时候自动创建。

当然这个问题还有别的解决方案,比如手动调用activiti提供的建表脚本创建等,相关教程可以很容易搜到。

猜你喜欢

转载自blog.csdn.net/icezcity/article/details/80859335
今日推荐