最近开发的一个提取数据的服务在适配mysql时出现了问题,用ResultSetMetaData.getColumnName获取的列名并非sql语句中设定的别名,导致结果集输出错误,代码如下:
for (int i = 1; i <= metaData.getColumnCount(); i++) {
map.put(metaData.getColumnName(i), resultSet.getObject(i));
}
其中错误的将getColumnName方法理解为getColumnLabel,所以在这里对两个方法做下说明。
首先看下JDBC中对这两个方法的定义
/**
* Gets the designated column's suggested title for use in printouts and
* displays. The suggested title is usually specified by the SQL <code>AS</code>
* clause. If a SQL <code>AS</code> is not specified, the value returned from
* <code>getColumnLabel</code> will be the same as the value returned by the
* <code>getColumnName</code> method.
*
* @param column the first column is 1, the second is 2, ...
* @return the suggested column title
* @exception SQLException if a database access error occurs
*/
String getColumnLabel(int column) throws SQLException;
/**
* Get the designated column's name.
*
* @param column the first column is 1, the second is 2, ...
* @return column name
* @exception SQLException if a database access error occurs
*/
String getColumnName(int column) throws SQLException;
注释说明getColumnLabel返回的是列标题,getColumnName返回的是列名,列标题和列名看起来是一个东西,其实并非这么简单,列标题是指select语句中的列别名,也就是查询结果集中显示出来的列,而列名指的是数据库表中的列名,以下边的sql为例
select c1 as label from t
getColumnLabel应该返回label,getColumnName应该返回c1。
当然,这只是JDBC对这两个方法的定义,在各个数据库驱动中对该方法的实现还有所不同。先来看下oracle的代码。
public String getColumnLabel(int var1) throws SQLException {
return this.getColumnName(var1);
}
public String getColumnName(int var1) throws SQLException {
int var2 = this.getValidColumnIndex(var1);
return this.statement.getDescriptionWithNames()[var2].columnName;
}
没错,getColumnLabel直接调用了getColumnName,也就是说在oracle中这两个其实是同一个方法,返回的是sql中的列别名。再来看下mysql的代码。
public String getColumnLabel(int column) throws SQLException {
return this.useOldAliasBehavior ? this.getColumnName(column) : this.getField(column).getColumnLabel();
}
public String getColumnName(int column) throws SQLException {
if (this.useOldAliasBehavior) {
return this.getField(column).getName();
} else {
String name = this.getField(column).getNameNoAliases();
return name != null && name.length() == 0 ? this.getField(column).getName() : name;
}
}
可以看到,mysql参照JDBC的定义,getColumnLabel返回了列别名,getColumnName返回了列名,同时mysql提供了一个useOldAliasBehavior参数,当其为true时,就会完全使用列别名当作列名,这个参数可以使用useOldAliasMetadataBehavior=true配置到url中,这时方法含义又和oracle中的相同了。
最后建议在代码中使用getColumnLabel,因为其在各个驱动版本中的含义是相同的,可以避免多数据库适配时出现的错误。
本文解析了JDBC中getColumnLabel与getColumnName方法的差异,解释了它们在Oracle与MySQL驱动中的具体实现,强调在多数据库适配时应使用getColumnLabel以避免错误。
1352

被折叠的 条评论
为什么被折叠?



