After MySQL uses the column alias, Hibernate still reads the original column name instead of the alias

phenomenon

hibernate cannot find the required field from the returned result set, such as user ﹣ name, when executing the program

Error message:

2020-05-15 10:37:01.330 [INFO][org.hibernate.type.StringType][nullSafeGet][180]-> could not read column value from result set: from_classifier_id; Column 'from_classifier_id' not found.
2020-05-15 10:37:01.332 [WARN][org.hibernate.util.JDBCExceptionReporter][logExceptions][77]-> SQL Error: 0, SQLState: S0022
2020-05-15 10:37:01.332 [ERROR][org.hibernate.util.JDBCExceptionReporter][logExceptions][78]-> Column 'from_classifier_id' not found.
[default][2020-05-15 10:37:01,334][ERROR][com.primeton.dgs.web.command.metamodel.PackageCommand][Line:442] Failed to load tree
org.hibernate.exception.SQLGrammarException: could not execute query
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
	at org.hibernate.loader.Loader.doList(Loader.java:2208)
	at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2102)
	at org.hibernate.loader.Loader.list(Loader.java:2097)

Troubleshooting process

First look at the source code of Hibernate, and finally find the following paragraph:

	protected void autoDiscoverTypes(ResultSet rs) {
		try {
            //Extract metadata from the result set, which contains the metadata of the column
			Metadata metadata = new Metadata( getFactory(), rs );
			List aliases = new ArrayList();
			List types = new ArrayList();

			rowProcessor.prepareForAutoDiscovery( metadata );
            //Loop to fetch from metadata and set rowProcessor's column name (data of those columns from the result set)
			for ( int i = 0; i < rowProcessor.columnProcessors.length; i++ ) {
                //When you go inside, you will call the code in MySQL driver to get the column name
				rowProcessor.columnProcessors[i].performDiscovery( metadata, types, aliases );
			}

			resultTypes = ArrayHelper.toTypeArray( types );
			transformerAliases = ArrayHelper.toStringArray( aliases );
		}
		catch ( SQLException e ) {
			throw new HibernateException( "Exception while trying to autodiscover types.", e );
		}
	}
		public void performDiscovery(Metadata metadata, List types, List aliases) throws SQLException {
			if ( alias == null ) {
                //Get the column name of the corresponding location from the metadata according to the location, and then look at the MySQL source code to find the root cause of the problem
				alias = metadata.getColumnName( position );
			}
			else if ( position < 0 ) {
				position = metadata.resolveColumnPosition( alias );
			}
			if ( type == null ) {
				type = metadata.getHibernateType( position );
			}
			types.add( type );
			aliases.add( alias );
		}

Look at the code in MySQL driver again, and finally find out why Hibernate gets the original column name instead of alias

    @Override
    public String getColumnName(int column) throws SQLException {
        if (this.useOldAliasBehavior) {
            return getField(column).getName();
        }

        String name = getField(column).getOriginalName();

        if (name == null) {
            return getField(column).getName();
        }

        return name;
    }

From the code, you can see this.useOldAliasBehavior, which indicates where the driver can be configured to return the original column name or alias, so go to find duniang for a moment

solve

Add a parameter to jdbc.url as follows:

jdbc.url=jdbc:mysql://www.test.com:3306/test?useOldAliasMetadataBehavior=true

Tags: Programming Hibernate Java MySQL JDBC

Posted on Fri, 15 May 2020 09:05:36 -0700 by usacascl