现象

执行程序时报hibernate从返回结果集中找不到需要的字段,比如user_name

错误信息:

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] 加载树失败
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)

问题排查过程

先看Hibernate的源码,最终找到了这么一段:

	protected void autoDiscoverTypes(ResultSet rs) {
		try {
            //从结果集中提取元数据,其中就包含了列的元数据
			Metadata metadata = new Metadata( getFactory(), rs );
			List aliases = new ArrayList();
			List types = new ArrayList();

			rowProcessor.prepareForAutoDiscovery( metadata );
            //循环从元数据中取并设置rowProcessor的列名(从结果集中取那些列的数据)
			for ( int i = 0; i < rowProcessor.columnProcessors.length; i++ ) {
                //在往里走就会去调用MySQL驱动中的代码,获取列名
				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 ) {
                //根据位置从元数据中获取对应位置的列名,再去看MySQL源码就会发现本次问题的根本原因
				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 );
		}

再看MySQL驱动中的代码,最终定位到了Hibernate为什么会取到最初的列名,而不是别名

    @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;
    }

从代码中可以看到this.useOldAliasBehavior,说明在哪里是可以配置驱动到底返回原始列名还是别名,所以找度娘为了一下

解决

在jdbc.url中要增加一个参数,如下:

09-01 21:49