简体   繁体   中英

Hibernate: Schema-validation: missing table - case-sensitive Mysql schema identifier turned upper-case

(context - migrating working Java server application from Spring/Hibernate 3 to 5)

Upon server start, the Hibernate validation fails with “ Schema-validation: missing table ”. The tables exist (the app is working with Hibernate 3)

The reason is the query [1] which fetches all tables from the DB informationSchema. The database name is 'myApp', but “WHERE (TABLE_SCHEMA = 'MYAPP')“ is queried. This leads to empty result set and “missing tables”.

The reason for that is the initial value of “unquotedCaseStrategy” [2] (IdentifierCaseStrategy.UPPER) which is left unchanged within “applyIdentifierCasing” method where all metaData.storesLowerCaseIdentifiers(),metaData.storesUpperCaseIdentifiers(),metaData.storesMixedCaseIdentifiers() return FALSE, because select @@lower_case_table_names called in MariaDbDatabaseMetaData#connection#getLowercaseTableNames() [4] method returns '0'. This is the default value for Unix systems and as the JavaDoc [5] states, all table names and aliases and database names are compared in a case-sensitive manner.

  • Hibernate = 5.6.7
  • Java = jdk1.8.0_241
  • AppServer = wildfly-18.0.1.Final
  • DB = MariaDb 10.1
  • DB driver = mariadb-java-client-2.2.6.jar

[1]

SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME, IF(TABLE_TYPE='BASE TABLE', 'TABLE', TABLE_TYPE) as TABLE_TYPE, TABLE_COMMENT REMARKS, NULL TYPE_CAT, NULL TYPE_SCHEM, NULL TYPE_NAME, NULL SELF_REFERENCING_COL_NAME, NULL REF_GENERATION FROM INFORMATION_SCHEMA.TABLES WHERE (TABLE_SCHEMA = 'MYAPP') AND (TABLE_NAME LIKE '%') AND TABLE_TYPE IN ('BASE TABLE','VIEW') ORDER BY TABLE_TYPE, TABLE_SCHEMA, TABLE_NAME;

[2] org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder#unquotedCaseStrategy

[3] org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder#applyIdentifierCasing

[4] org.mariadb.jdbc.MariaDbConnection#getLowercaseTableNames

[5] getLowercaseTableNames Javadoc: - Are table case sensitive or not. Default Value: 0 (Unix), 1 (Windows), 2 (Mac OS X). If set to 0 (the default on Unix-based systems), table names and aliases and database names are compared in a case-sensitive manner. If set to 1 (the default on Windows), names are stored in lowercase and not compared in a case-sensitive manner. If set to 2 (the default on Mac OS X), names are stored as declared, but compared in lowercase.

It seems to me there is an error in the applyIdentifierCasing method logic and the default (initial value) of the unquotedCaseStrategy strategy [2] should be IdentifierCaseStrategy.MIXED.

WORKAROUND: extend one of the Dialects in org.hibernate.dialect and @Override buildIdentifierHelper() method directly returning the IdentifierHelper instance (calling builder.build(); instead of super.buildIdentifierHelper(…) which would overwrite the config).

public class MySQL5InnoDBDialectEx extends MySQL55Dialect {

    public MySQL5InnoDBDialectEx() {
        super();
        registerColumnType(Types.BIT, "tinyint(1)");
    }

    @Override
    public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException {

        // Copied from org.hibernate.dialect.Dialect#buildIdentifierHelper..
        builder.applyReservedWords(dbMetaData);
        builder.applyReservedWords(AnsiSqlKeywords.INSTANCE.sql2003());

        builder.setUnquotedCaseStrategy(IdentifierCaseStrategy.MIXED);
        builder.setQuotedCaseStrategy(IdentifierCaseStrategy.MIXED);

        // DO NOT USE   >>return super.buildIdentifierHelper( builder, dbMetaData );<<
        // as is normally done in the superClasses, because it overwrites the Quoted/UnquotedCaseStrategy  (that is a bug..)
        return builder.build();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM