解决Mybatis-Generator单实例不同数据库同表名生成代码读取错误

事故现场

我在项目开发中,由于项目业务需求出现多分支,各个分支的数据结构都是由初始业务演化而来。在开发环境中部署的是单实例MySQL,各分支采用数据库隔离,但数据表名仍相同,差异体现在数据列。当我在A分支的A数据库A表增加A字段后,再生成B分支的B数据库B表的代码。此时问题就出现了,生成的代码中包含A表的A字段,然而这并不是我想要的。

问题排查

mybatis-generator-core版本:1.4.0
代码生成的本质其实就是读取所连接数据库information_schema.columns表的数据,然后解析所属数据库|所属表|字段类型,然后进行处理后再生成代码。出现问题,百科了下没啥有用的方法(也可能是我百科手段比较简单),于是乎只有老老实实Debug。经过Debug跟踪发现其获取列在org.mybatis.generator.internal.db.DatabaseIntrospector#getColumns,代码如下:

private Map<ActualTableName, List<IntrospectedColumn>> getColumns(TableConfiguration tc) throws SQLException {
    
    
        boolean delimitIdentifiers = tc.isDelimitIdentifiers() || StringUtility.stringContainsSpace(tc.getCatalog()) || StringUtility.stringContainsSpace(tc.getSchema()) || StringUtility.stringContainsSpace(tc.getTableName());
        String localCatalog;
        String localSchema;
        String localTableName;
        if (delimitIdentifiers) {
    
    
            localCatalog = tc.getCatalog();
            localSchema = tc.getSchema();
            localTableName = tc.getTableName();
        } else if (this.databaseMetaData.storesLowerCaseIdentifiers()) {
    
    
            localCatalog = tc.getCatalog() == null ? null : tc.getCatalog().toLowerCase();
            localSchema = tc.getSchema() == null ? null : tc.getSchema().toLowerCase();
            localTableName = tc.getTableName() == null ? null : tc.getTableName().toLowerCase();
        } else if (this.databaseMetaData.storesUpperCaseIdentifiers()) {
    
    
            localCatalog = tc.getCatalog() == null ? null : tc.getCatalog().toUpperCase();
            localSchema = tc.getSchema() == null ? null : tc.getSchema().toUpperCase();
            localTableName = tc.getTableName() == null ? null : tc.getTableName().toUpperCase();
        } else {
    
    
            localCatalog = tc.getCatalog();
            localSchema = tc.getSchema();
            localTableName = tc.getTableName();
        }

        if (tc.isWildcardEscapingEnabled()) {
    
    
            String escapeString = this.databaseMetaData.getSearchStringEscape();
            StringBuilder sb = new StringBuilder();
            StringTokenizer st;
            String token;
            if (localSchema != null) {
    
    
                st = new StringTokenizer(localSchema, "_%", true);

                while(true) {
    
    
                    if (!st.hasMoreTokens()) {
    
    
                        localSchema = sb.toString();
                        break;
                    }

                    token = st.nextToken();
                    if (token.equals("_") || token.equals("%")) {
    
    
                        sb.append(escapeString);
                    }

                    sb.append(token);
                }
            }

            sb.setLength(0);

            for(st = new StringTokenizer(localTableName, "_%", true); st.hasMoreTokens(); sb.append(token)) {
    
    
                token = st.nextToken();
                if (token.equals("_") || token.equals("%")) {
    
    
                    sb.append(escapeString);
                }
            }

            localTableName = sb.toString();
        }

        Map<ActualTableName, List<IntrospectedColumn>> answer = new HashMap();
        if (this.logger.isDebugEnabled()) {
    
    
            String fullTableName = StringUtility.composeFullyQualifiedTableName(localCatalog, localSchema, localTableName, '.');
            this.logger.debug(Messages.getString("Tracing.1", fullTableName));
        }
		// 这里就是Mybatis-Generator获取列的来源,由于我的项目特殊性,没有指定catalog和schema
        ResultSet rs = this.databaseMetaData.getColumns(localCatalog, localSchema, localTableName, "%");
        boolean supportsIsAutoIncrement = false;
        boolean supportsIsGeneratedColumn = false;
        ResultSetMetaData rsmd = rs.getMetaData();
        int colCount = rsmd.getColumnCount();

        for(int i = 1; i <= colCount; ++i) {
    
    
            if ("IS_AUTOINCREMENT".equals(rsmd.getColumnName(i))) {
    
    
                supportsIsAutoIncrement = true;
            }

            if ("IS_GENERATEDCOLUMN".equals(rsmd.getColumnName(i))) {
    
    
                supportsIsGeneratedColumn = true;
            }
        }

        while(rs.next()) {
    
    
            IntrospectedColumn introspectedColumn = ObjectFactory.createIntrospectedColumn(this.context);
            introspectedColumn.setTableAlias(tc.getAlias());
            introspectedColumn.setJdbcType(rs.getInt("DATA_TYPE"));
            introspectedColumn.setActualTypeName(rs.getString("TYPE_NAME"));
            introspectedColumn.setLength(rs.getInt("COLUMN_SIZE"));
            introspectedColumn.setActualColumnName(rs.getString("COLUMN_NAME"));
            introspectedColumn.setNullable(rs.getInt("NULLABLE") == 1);
            introspectedColumn.setScale(rs.getInt("DECIMAL_DIGITS"));
            introspectedColumn.setRemarks(rs.getString("REMARKS"));
            introspectedColumn.setDefaultValue(rs.getString("COLUMN_DEF"));
            if (supportsIsAutoIncrement) {
    
    
                introspectedColumn.setAutoIncrement("YES".equals(rs.getString("IS_AUTOINCREMENT")));
            }

            if (supportsIsGeneratedColumn) {
    
    
                introspectedColumn.setGeneratedColumn("YES".equals(rs.getString("IS_GENERATEDCOLUMN")));
            }

            ActualTableName atn = new ActualTableName(rs.getString("TABLE_CAT"), rs.getString("TABLE_SCHEM"), rs.getString("TABLE_NAME"));
            List<IntrospectedColumn> columns = (List)answer.get(atn);
            if (columns == null) {
    
    
                columns = new ArrayList();
                answer.put(atn, columns);
            }

            ((List)columns).add(introspectedColumn);
            if (this.logger.isDebugEnabled()) {
    
    
                this.logger.debug(Messages.getString("Tracing.2", introspectedColumn.getActualColumnName(), Integer.toString(introspectedColumn.getJdbcType()), atn.toString()));
            }
        }

        this.closeResultSet(rs);
        if (answer.size() > 1 && !StringUtility.stringContainsSQLWildcard(localSchema) && !StringUtility.stringContainsSQLWildcard(localTableName)) {
    
    
            ActualTableName inputAtn = new ActualTableName(tc.getCatalog(), tc.getSchema(), tc.getTableName());
            StringBuilder sb = new StringBuilder();
            boolean comma = false;

            ActualTableName atn;
            for(Iterator var15 = answer.keySet().iterator(); var15.hasNext(); sb.append(atn.toString())) {
    
    
                atn = (ActualTableName)var15.next();
                if (comma) {
    
    
                    sb.append(',');
                } else {
    
    
                    comma = true;
                }
            }

            this.warnings.add(Messages.getString("Warning.25", inputAtn.toString(), sb.toString()));
        }

        return answer;
    }

其中的this.databaseMetaData.getColumns最终是调用的mysql驱动包的com.mysql.cj.jdbc.DatabaseMetaDataUsingInfoSchema#getColumns里未获取到db导致的读取数据列定义错乱。

String db = this.getDatabase(catalog, schemaPattern);
db = this.pedantic ? db : StringUtils.unQuoteIdentifier(db, this.quotedId);

com.mysql.cj.jdbc.DatabaseMetaData#getDatabase代码如下:

protected String getDatabase(String catalog, String schema) {
    
    
        if (this.databaseTerm.getValue() == DatabaseTerm.SCHEMA) {
    
    
            return schema == null && (Boolean)this.nullDatabaseMeansCurrent.getValue() ? this.database : schema;
        } else {
    
    
            return catalog == null && (Boolean)this.nullDatabaseMeansCurrent.getValue() ? this.database : catalog;
        }
    }

关于的nullDatabaseMeansCurrent官网原文链接
关于的nullDatabaseMeansCurren的官网原文
其原文大致意思是:提供给DatabaseMetaData方法的 catalog 或 schema 参数值为null时,是否意味着使用当前数据库

解决方案

在jdbc连接url中增加参数nullDatabaseMeansCurrent=true指定使用当前数据库

猜你喜欢

转载自blog.csdn.net/baidu_38956956/article/details/128629780