比尔云BierYun--阿里云最新优惠活动
阿里云优惠码丨阿里云代金券

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

一个MySql实例自动创建多个Activiti数据库问题http://www.bieryun.com/4479.html

一次使用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中,有这样一个方法:

  1. public void performSchemaOperationsProcessEngineBuild() {
  2. String databaseSchemaUpdate = Context.getProcessEngineConfiguration().getDatabaseSchemaUpdate();
  3. log.debug(“Executing performSchemaOperationsProcessEngineBuild with setting “ + databaseSchemaUpdate);
  4. if (ProcessEngineConfigurationImpl.DB_SCHEMA_UPDATE_DROP_CREATE.equals(databaseSchemaUpdate)) {
  5. try {
  6. dbSchemaDrop();
  7. } catch (RuntimeException e) {
  8. // ignore
  9. }
  10. }
  11. if (org.activiti.engine.ProcessEngineConfiguration.DB_SCHEMA_UPDATE_CREATE_DROP.equals(databaseSchemaUpdate)
  12. || ProcessEngineConfigurationImpl.DB_SCHEMA_UPDATE_DROP_CREATE.equals(databaseSchemaUpdate) || ProcessEngineConfigurationImpl.DB_SCHEMA_UPDATE_CREATE.equals(databaseSchemaUpdate)) {
  13. dbSchemaCreate();
  14. } else if (org.activiti.engine.ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE.equals(databaseSchemaUpdate)) {
  15. dbSchemaCheckVersion();
  16. } else if (ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE.equals(databaseSchemaUpdate)) {
  17. dbSchemaUpdate();
  18. }
  19. }

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

dbSchemaUpdate();

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

  1. public String dbSchemaUpdate() {
  2. String feedback = null;
  3. boolean isUpgradeNeeded = false;
  4. int matchingVersionIndex = –1;
  5. if (isEngineTablePresent()) {
  6. PropertyEntity dbVersionProperty = selectById(PropertyEntity.class, “schema.version”);
  7. String dbVersion = dbVersionProperty.getValue();
  8. ……
  9. }else {
  10. dbSchemaCreateEngine();
  11. }

 

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

schema.version

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

那为什么

isEngineTablePresent()

方法会判断为true呢?

  1. public boolean isEngineTablePresent() {
  2. return isTablePresent(“ACT_RU_EXECUTION”);通过判断表ACT_RU_EXECUTION是否存在
  3. }
  1. public boolean isTablePresent(String tableName) {
  2. // ACT-1610: in case the prefix IS the schema itself, we don’t add the
  3. // prefix, since the check is already aware of the schema
  4. if (!dbSqlSessionFactory.isTablePrefixIsSchema()) {
  5. tableName = prependDatabaseTablePrefix(tableName);
  6. }
  7. Connection connection = null;
  8. try {
  9. connection = sqlSession.getConnection();
  10. DatabaseMetaData databaseMetaData = connection.getMetaData();
  11. ResultSet tables = null;
  12. String catalog = this.connectionMetadataDefaultCatalog;
  13. if (dbSqlSessionFactory.getDatabaseCatalog() != null && dbSqlSessionFactory.getDatabaseCatalog().length() > 0) {
  14. catalog = dbSqlSessionFactory.getDatabaseCatalog();
  15. }
  16. String schema = this.connectionMetadataDefaultSchema;
  17. if (dbSqlSessionFactory.getDatabaseSchema() != null && dbSqlSessionFactory.getDatabaseSchema().length() > 0) {
  18. schema = dbSqlSessionFactory.getDatabaseSchema();
  19. }
  20. String databaseType = dbSqlSessionFactory.getDatabaseType();
  21. if (“postgres”.equals(databaseType)) {
  22. tableName = tableName.toLowerCase();
  23. }
  24. if (schema != null && “oracle”.equals(databaseType)) {
  25. schema = schema.toUpperCase();
  26. }
  27. if (catalog != null && catalog.length() == 0) {
  28. catalog = null;
  29. }
  30. try {
  31. tables = databaseMetaData.getTables(catalog, schema, tableName, JDBC_METADATA_TABLE_TYPES);
  32. return tables.next();
  33. } finally {
  34. try {
  35. tables.close();
  36. } catch (Exception e) {
  37. log.error(“Error closing meta data tables”, e);
  38. }
  39. }
  40. } catch (Exception e) {
  41. throw new ActivitiException(“couldn’t check if tables are already present using metadata: “ + e.getMessage(), e);
  42. }
  43. }

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

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

ACT_RU_EXECUTION

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

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

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

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

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

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

原文地址https://blog.csdn.net/icezcity/article/details/80859335

未经允许不得转载:阿里云代理商 » 一个MySql实例自动创建多个Activiti数据库问题
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

强烈推荐

高性能SSD云服务器ECS抗攻击,高可用云数据库RDS