最近在写一个功能的时候遇到一个问题,今天刚好有空,就把他记录下来。
问题是这样的,在做一个很普通的查询功能,结果却出现了问题。问题是查出来莫名少了一些列,就是说用代码查出来的数据和用数据库客户端查出来的数据不一致,也不报错。这可让我百思不得其解。sql类似如下:
第一种:
SELECT
*
FROM
TEST A
LEFT JOIN TEST_1 I ON A.DOMAIN_CODE = I.VERSION_ID;
第二种:
SELECT
A.*, I.*
FROM
TEST A,
TEST_1 I
WHERE
A.DOMAIN_CODE = I.VERSION_ID;
第三种:
SELECT
A.ID AS A_ID,
A.CREATE_DATE AS A_CREATE_DATE,
I.ID AS I_ID,
I.CREATE_DATE AS I_CREATE_DATE
FROM
TEST A
LEFT JOIN TEST_1 I ON A.ID = I.ID;
但是不管怎么查,最后查询出来的结果列少了一些,而且数据也都有。
遇到这个比较棘手的问题,无奈之下去看了一下用的框架的底层代码,
大致的意思是这样的:
DBUtil dbutil = DBUtil.getInstance();
try {
Connection conn = dbutil.getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData() ;
int columnCount = rsmd.getColumnCount();
ArrayList ret = new ArrayList();
String[] colNames = new String[columnCount];
int i;
for(int bo = 0; bo < colNames.length; ++bo) {
i = bo + 1;
colNames[bo] = rsmd.getColumnName(i);
if(colNames[bo] != null) {
colNames[bo] = colNames[bo].toUpperCase();
}
}
while(rs.next()) {
Map var11 = new HashMap();
for(i = 1; i <= columnCount; ++i) {
var11.put(colNames[i - 1], rs.getString(i));
}
ret.add(var11);
}
return ret;
} catch (Exception e) {
e.printStackTrace();
}
相信代码很容易看懂,为了返回一个装有Map的List,先用ResultSetMetaData去查询了结果集的列的信息,然后在根据列名组装结果集的数据并返回,乍一看没什么问题。别忘了我这篇文章的标题,我把列名打印出来之后,仔细一想就会发现问题所在了:
由于我的两张表的数据列有几列列名相同,而getColumnName取的是数据库表的原始列名,这样查出来的列数固然是正确的,然而在ResuleSet往Map集合里面装数据的时候,由于Key值相同,后面的列数据覆盖了前面添加的列数据,因此查询返回后的结果集列少了一些。别忘了HashMap是不允许键值重复的,到此发现了问题的所在。
然后开始解决问题,翻遍了API发现了一个方法似乎可行,
这个方法取Select的字段别名,那么我在写Sql的时候让字段别名不重复不就行了吗,所以,用下面的代码代替上面的:
colNames[bo] = rsmd.getColumnLabel(i);
至此问题解决。