Activiti重複建表bug

故障碼

  故障碼如下:

2019-11-11 16:05:27.318  INFO 19208 --- [           main] o.activiti.engine.impl.db.DbSqlSession   : performing create on history with resource org/activiti/db/create/activiti.mysql.create.history.sql
2019-11-11 16:05:27.338  INFO 19208 --- [           main] o.activiti.engine.impl.db.DbSqlSession   : Found MySQL: majorVersion=5 minorVersion=7
2019-11-11 16:05:27.643  INFO 19208 --- [           main] o.activiti.engine.impl.db.DbSqlSession   : performing create on identity with resource org/activiti/db/create/activiti.mysql.create.identity.sql
2019-11-11 16:05:27.643  INFO 19208 --- [           main] o.activiti.engine.impl.db.DbSqlSession   : Found MySQL: majorVersion=5 minorVersion=7
2019-11-11 16:05:27.708 ERROR 19208 --- [           main] o.activiti.engine.impl.db.DbSqlSession   : problem during schema create, statement alter table ACT_ID_MEMBERSHIP 
add constraint ACT_FK_MEMB_GROUP 
foreign key (GROUP_ID_) 
references ACT_ID_GROUP (ID_)

java.sql.SQLIntegrityConstraintViolationException: Can't write; duplicate key in table '#sql-345e_4030'
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:782) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:666) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	at com.alibaba.druid.filter.FilterChainImpl.statement_execute(FilterChainImpl.java:2958) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.filter.FilterAdapter.statement_execute(FilterAdapter.java:2473) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.filter.FilterEventAdapter.statement_execute(FilterEventAdapter.java:188) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.filter.FilterChainImpl.statement_execute(FilterChainImpl.java:2956) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.proxy.jdbc.StatementProxyImpl.execute(StatementProxyImpl.java:147) ~[druid-1.1.10.jar:1.1.10]
	at com.alibaba.druid.pool.DruidPooledStatement.execute(DruidPooledStatement.java:619) ~[druid-1.1.10.jar:1.1.10]
	at org.activiti.engine.impl.db.DbSqlSession.executeSchemaResource(DbSqlSession.java:1311) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.db.DbSqlSession.executeSchemaResource(DbSqlSession.java:1231) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.db.DbSqlSession.executeMandatorySchemaResource(DbSqlSession.java:1016) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.db.DbSqlSession.dbSchemaCreateIdentity(DbSqlSession.java:985) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.db.DbSqlSession.dbSchemaUpdate(DbSqlSession.java:1087) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.db.DbSqlSession.performSchemaOperationsProcessEngineBuild(DbSqlSession.java:1422) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.SchemaOperationsProcessEngineBuild.execute(SchemaOperationsProcessEngineBuild.java:27) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:24) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:57) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:47) [activiti-spring-5.22.0.jar:5.22.0]
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) [spring-tx-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.activiti.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:45) [activiti-spring-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:31) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:40) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.ProcessEngineImpl.<init>(ProcessEngineImpl.java:80) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl.buildProcessEngine(ProcessEngineConfigurationImpl.java:613) [activiti-engine-5.22.0.jar:5.22.0]
	at org.activiti.spring.SpringProcessEngineConfiguration.buildProcessEngine(SpringProcessEngineConfiguration.java:65) [activiti-spring-5.22.0.jar:5.22.0]
	at org.activiti.spring.ProcessEngineFactoryBean.getObject(ProcessEngineFactoryBean.java:60) [activiti-spring-5.22.0.jar:5.22.0]
	at org.activiti.spring.ProcessEngineFactoryBean.getObject(ProcessEngineFactoryBean.java:32) [activiti-spring-5.22.0.jar:5.22.0]
	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:163) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:101) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1645) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getObjectForBeanInstance(AbstractAutowireCapableBeanFactory.java:1178) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:327) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1065) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:815) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:721) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:470) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1250) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1099) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:541) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:501) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1065) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:373) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1344) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:578) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:501) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:760) [spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) ~[spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:395) ~[spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) ~[spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255) ~[spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243) ~[spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
	at com.weifu.Application.main(Application.java:30) ~[classes/:na]

分析

  上面的故障碼是說,Activiti在執行activiti.mysql.create.identity.sqlDDL文件時報錯。

  於是我們就找到jar包中的該文件,打開該文件,其內容如下:

create table ACT_ID_GROUP (
    ID_ varchar(64),
    REV_ integer,
    NAME_ varchar(255),
    TYPE_ varchar(255),
    primary key (ID_)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin;

create table ACT_ID_MEMBERSHIP (
    USER_ID_ varchar(64),
    GROUP_ID_ varchar(64),
    primary key (USER_ID_, GROUP_ID_)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin;

create table ACT_ID_USER (
    ID_ varchar(64),
    REV_ integer,
    FIRST_ varchar(255),
    LAST_ varchar(255),
    EMAIL_ varchar(255),
    PWD_ varchar(255),
    PICTURE_ID_ varchar(64),
    primary key (ID_)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin;

create table ACT_ID_INFO (
    ID_ varchar(64),
    REV_ integer,
    USER_ID_ varchar(64),
    TYPE_ varchar(64),
    KEY_ varchar(255),
    VALUE_ varchar(255),
    PASSWORD_ LONGBLOB,
    PARENT_ID_ varchar(255),
    primary key (ID_)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin;

alter table ACT_ID_MEMBERSHIP 
    add constraint ACT_FK_MEMB_GROUP 
    foreign key (GROUP_ID_) 
    references ACT_ID_GROUP (ID_);

alter table ACT_ID_MEMBERSHIP 
    add constraint ACT_FK_MEMB_USER 
    foreign key (USER_ID_) 
    references ACT_ID_USER (ID_);

  在上面的提示中,找到最關鍵的信息,那就是:

2019-11-11 16:05:27.708 ERROR 19208 --- [           main] o.activiti.engine.impl.db.DbSqlSession   : problem during schema create, statement alter table ACT_ID_MEMBERSHIP 
add constraint ACT_FK_MEMB_GROUP 
foreign key (GROUP_ID_) 
references ACT_ID_GROUP (ID_)

  其對應的activiti.mysql.create.identity.sql指令爲:

alter table ACT_ID_MEMBERSHIP 
    add constraint ACT_FK_MEMB_GROUP 
    foreign key (GROUP_ID_) 
    references ACT_ID_GROUP (ID_);

  通過查ACT_ID_MEMBERSHIP表,我們發現,在數據庫中存在兩張表名一樣的表,分別是act_id_membershipACT_ID_MEMBERSHIP。但是不同之處在於,一張是小寫的表名,一張是大寫的表名,要知道,在Windows中創建的MySQL,本身是不會出現兩張相同的表名的,也就是說,數據庫表名其實是在創建時就已經不區分大小寫了,故不能在創建act_id_membership後再創建ACT_ID_MEMBERSHIP,否則就出現問題。

  而這裏是出現了兩張表名一樣的表,分別是act_id_membershipACT_ID_MEMBERSHIP,這說明此時的MySQL其實配置的是區分大小寫,只有這樣上述兩張表才能夠共存。

  爲了驗證上述猜想,我們可以通過執行下面的語句得知:

SHOW  VARIABLES LIKE 'lower_case_table_names';

  如果查詢的結果顯示lower_case_table_names0,則是區分大小寫,如果顯示爲1則是不區分大小寫。而上面LinuxMySQL的查詢結果爲0,這說明,此時的LinuxMySQL是區分大小寫的。

  然後我們再查看act_id_membership的建表語句:

CREATE TABLE `act_id_membership` (
  `USER_ID_` varchar(64) COLLATE utf8_bin NOT NULL,
  `GROUP_ID_` varchar(64) COLLATE utf8_bin NOT NULL,
  PRIMARY KEY (`USER_ID_`,`GROUP_ID_`),
  KEY `ACT_FK_MEMB_GROUP` (`GROUP_ID_`),
  CONSTRAINT `ACT_FK_MEMB_GROUP` FOREIGN KEY (`GROUP_ID_`) REFERENCES `act_id_group` (`ID_`),
  CONSTRAINT `ACT_FK_MEMB_USER` FOREIGN KEY (`USER_ID_`) REFERENCES `act_id_user` (`ID_`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin

  我們發現,儘管說原來的表名是小寫的,但是其中的外鍵約束仍然爲大寫,而再執行ACT_ID_MEMBERSHIP中的下述修改語句時,就會出錯。

alter table ACT_ID_MEMBERSHIP 
    add constraint ACT_FK_MEMB_GROUP 
    foreign key (GROUP_ID_) 
    references ACT_ID_GROUP (ID_);

  因爲此時在同一張表中,出現了兩個相同的外鍵約束ACT_FK_MEMB_GROUP,故此時後一個修改失敗,於是就出現了上面的情況。

解決辦法

  上面的問題,其實是由於Activiti在啓動後,發現數據庫中不存在工作流相關的數據表,於是就自動啓動了建表操作。而原數據庫中,本身是存在相應的工作流數據表(表名全部小寫),只是由於數據庫部署在Linux中,而Linux中部署的MySQL數據庫,其默認是區分大小寫的,於是Activiti按照大寫的表名查表,發現找不到,這才創建了新的大寫的數據表,於是就引發了上面的問題。

  而該問題我在之前的文章Docker中安裝MySQL有論述,這裏可以參考之前的文章內容。

  在瞭解了這裏之後,我們自然也就想到了解決辦法,那就是將Linux中的大小寫配置與Windows中的相統一,也就是說讓Linux中的MySQL,也不去區分數據表的大小寫,我們可以通過修改Linux中的配置文件my.cnf,在其中添加上如下配置:

lower_case_table_names=1

  重啓MySQL,該問題解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章