现象
执行程序时报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中要增加一个参数,如下: