学习笔记:一个MySQL实例有多个Activiti数据库问题
学习笔记:一个MySQL实例有多个Activiti数据库问题
使用SpringBoot + activiti6 搭建审批流项目,数据库使用的是MySQL.且我的数据库下存在多个activiti相关的数据库 schema.
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>6.0.0</version>
</dependency>
配置文件
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/activiti6?useUnicode=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.activiti.check-process-definitions=false
spring.activiti.database-schema-update=true
因为我的数据库下已经存在了一个activiti7的数据库,所以我这次又新建了一个activiti6的数据库,然后在启动的时候没有自动创建表,而是直接进行了activiti 表的查询,并报了如下的错误
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Table 'activiti6.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 'activiti6.act_ge_property' doesn't exist
然后我就开始跟断点看源码查找问题,发现它走到了如下这段代码 org.activiti.engine.impl.db.DbSqlSession (中间代码省略了一部分)
public String dbSchemaUpdate() {
String feedback = null;
boolean isUpgradeNeeded = false;
int matchingVersionIndex = -1;
if (isEngineTablePresent()) {
PropertyEntity dbVersionProperty = selectById(PropertyEntity.class, "schema.version");
....
}else {
dbSchemaCreateEngine();
}
按预想建的是空白数据库,应该要走else的逻辑,怎么会进到if里面呢,我又继续跟了 isEngineTablePresent 这个方法,很简短,就是看数据库里面表是否存在
public boolean isEngineTablePresent() {
return isTablePresent("ACT_RU_EXECUTION");
}
继续看 isTablePresent 方法,问题就出在下面这段代码上了,这个tables返回有内容,导致tables.next()为true
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);
}
}
继续看, DatabaseMetaData 是一个接口,断点进到了下面 com.zaxxer.hikari.pool.HikariProxyDatabaseMetaData#getTables ,接着调用父类的 com.zaxxer.hikari.pool.ProxyDatabaseMetaData#getTables 方法.
public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException {
ResultSet resultSet = this.delegate.getTables(catalog, schemaPattern, tableNamePattern, types);
Statement statement = resultSet.getStatement();
if (statement != null) {
statement = ProxyFactory.getProxyStatement(this.connection, statement);
}
return ProxyFactory.getProxyResultSet(this.connection, (ProxyStatement)statement, resultSet);
}
this.delegate.getTables(catalog, schemaPattern, tableNamePattern, types); 这段代码进到了 com.mysql.cj.jdbc.DatabaseMetaDataUsingInfoSchema 这个类中.
@Override
public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException {
String db = getDatabase(catalog, schemaPattern);
db = this.pedantic ? db : StringUtils.unQuoteIdentifier(db, this.quotedId);
...
}
继续跟 getDatabase() 方法.该方法实现在父类 com.mysql.cj.jdbc.DatabaseMetaData 中
protected String getDatabase(String catalog, String schema) {
if (this.databaseTerm.getValue() == DatabaseTerm.SCHEMA) {
return schema == null && this.nullDatabaseMeansCurrent.getValue() ? this.database : schema;
}
return catalog == null && this.nullDatabaseMeansCurrent.getValue() ? this.database : catalog;
}
这个时候就看到了schema和catelog的都是null,然后继续跟下去的话sql就变成了如下
SELECT TABLE_SCHEMA AS TABLE_CAT, NULL AS TABLE_SCHEM, TABLE_NAME, CASE WHEN TABLE_TYPE='BASE TABLE' THEN CASE WHEN TABLE_SCHEMA = 'mysql' OR TABLE_SCHEMA = 'performance_schema' THEN 'SYSTEM TABLE' ELSE 'TABLE' END WHEN TABLE_TYPE='TEMPORARY' THEN 'LOCAL_TEMPORARY' ELSE TABLE_TYPE END AS TABLE_TYPE, TABLE_COMMENT AS REMARKS, NULL AS TYPE_CAT, NULL AS TYPE_SCHEM, NULL AS TYPE_NAME, NULL AS SELF_REFERENCING_COL_NAME, NULL AS REF_GENERATION FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'ACT_RU_EXECUTION' HAVING TABLE_TYPE IN ('TABLE',null,null,null,null) ORDER BY TABLE_TYPE, TABLE_SCHEMA, TABLE_NAME
根据这个sql执行的结果可以看到我的数据库中是存在数据的
学习笔记:一个MySQL实例有多个Activiti数据库问题
然后就可开始看为什么catalog为null呢,然后就继续看 nullDatabaseMeansCurrent 这个属性(其实跟到getDatabase()方法的时候已经进到了mysql-connector-java的类中了).
这个属性在 com.mysql.cj.jdbc.DatabaseMetaData 的定义为
protected RuntimeProperty<Boolean> nullDatabaseMeansCurrent;
看该类的构造方法可以看到
protected DatabaseMetaData(JdbcConnection connToSet, String databaseToSet, ResultSetFactory resultSetFactory) {
this.conn = connToSet;
this.session = (NativeSession) connToSet.getSession();
this.database = databaseToSet;
this.resultSetFactory = resultSetFactory;
this.exceptionInterceptor = this.conn.getExceptionInterceptor();
this.databaseTerm = this.conn.getPropertySet().<DatabaseTerm>getEnumProperty(PropertyKey.databaseTerm);
this.nullDatabaseMeansCurrent = this.conn.getPropertySet().getBooleanProperty(PropertyKey.nullDatabaseMeansCurrent);
this.pedantic = this.conn.getPropertySet().getBooleanProperty(PropertyKey.pedantic).getValue();
this.tinyInt1isBit = this.conn.getPropertySet().getBooleanProperty(PropertyKey.tinyInt1isBit).getValue();
this.transformedBitIsBoolean = this.conn.getPropertySet().getBooleanProperty(PropertyKey.transformedBitIsBoolean).getValue();
this.useHostsInPrivileges = this.conn.getPropertySet().getBooleanProperty(PropertyKey.useHostsInPrivileges).getValue();
this.quotedId = this.session.getIdentifierQuoteString();
}
在 com.mysql.cj.conf.PropertyKey 类中可以看到
nullDatabaseMeansCurrent("nullDatabaseMeansCurrent", "nullCatalogMeansCurrent", true), //
然后跟到 com.mysql.cj.conf.DefaultPropertySet
public DefaultPropertySet() {
for (PropertyDefinition<?> pdef : PropertyDefinitions.PROPERTY_KEY_TO_PROPERTY_DEFINITION.values()) {
addProperty(pdef.createRuntimeProperty());
}
}
可以看到 PropertyDefinitions.PROPERTY_KEY_TO_PROPERTY_DEFINITION
跟到 com.mysql.cj.conf.PropertyDefinitions 类中,果然发现了 nullDatabaseMeansCurrent 的定义.
new BooleanPropertyDefinition(PropertyKey.nullDatabaseMeansCurrent, DEFAULT_VALUE_FALSE, RUNTIME_MODIFIABLE,
Messages.getString("ConnectionProperties.nullCatalogMeansCurrent"), "3.1.8", CATEGORY_METADATA, Integer.MIN_VALUE),
可以看到他的默认值为false.
然后我们在配置文件的数据库链接上加上 &nullCatalogMeansCurrent=true ,然后重新执行程序.发现数据库表插入正常.问题解决.
最后的配置文件:
spring.datasource.url=jdbc:mysql://localhost:3306/activiti6?useUnicode=utf8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
spring.datasource.username=root
spring.datasource.password=123456
spring.activiti.check-process-definitions=false
spring.activiti.database-schema-update=true
来源:https://www.tuicool.com/articles/nqEfqa 欢迎关注微信公众号【慕容千语】,干货满满哦
- WebFont 三宗罪之二:吹毛求疵的WebFont 渲染差异
- IDC发布IT转型报告,现代化、自动化、转型三要素必不可少
- 存储过程和触发器的应用
- 两部委印发车联网产业标准体系建设指南 提到了自动驾驶
- 状态开关按钮ToggleButton
- 微软开放 .NET 框架源代码
- Angularjs基础(十二)
- 妙趣横生的HTML5 Page Visibility API
- 禁止/移除 WordPress 4.2 中前台自动加载的 emjo 脚本
- 项目管理方面的几个.NET开源项目
- 如何向十岁以下的朋友解释编程?这个说法碉堡了!
- 快速比较和合并文件
- 前端页面中 iOS 版微信长按识别二维码的bug 与解决方案
- .NET Mass Downloader -整体下载.NET源码
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- 如何将CentOS7升级至CentOS8(详细步骤)
- leetcode树之二叉树的所有路径
- 如何利用Bash脚本监控Linux的内存使用情况
- Ubuntu18 给terminal改个漂亮的命令行提示符的方法
- leetcode树之将有序数组转换为二叉搜索树
- 在 Ubuntu 上安装 Protobuf 3 的教程详解
- protobuf简单介绍和ubuntu 16.04环境下安装教程
- Ubuntu解决火狐浏览器无法同步书签的问题【推荐】
- Ubuntu添加swap分区的方法
- linux文件目录管理命令整理总结
- C++核心准则SF.8:为所有的.h文件使用包含监护
- 利用logsave如何将命令输出保存起来
- CentOs下安装gcc/g++/gdb的方法
- 详解firewall的规则设置与命令(白名单设置)
- 二叉树:构造一棵最大的二叉树