關(guān)于commons dbutils組件的一個(gè)小缺陷分析
Posted on 2011-02-12 17:33 寒武紀(jì) 閱讀(3032) 評(píng)論(7) 編輯 收藏 所屬分類: 數(shù)據(jù)庫(kù) 、Java 非常喜歡這種輕量級(jí)的JDBC封裝,比起Hibernate和iBatis,可以非常自由和靈活地運(yùn)用和自行二次封裝,由于dbutils的BeanHandler轉(zhuǎn)換方式采取了反射技術(shù),在性能上肯定有所損失,所以項(xiàng)目中基本上都使用MapHandler方式來轉(zhuǎn)換數(shù)據(jù),當(dāng)然就是自己寫的代碼多一點(diǎn),也無所謂。一般的查詢、子查詢、聯(lián)合查詢、包括視圖查詢等等都很正常,但是發(fā)現(xiàn)一個(gè)比較小的問題,就是在使用聚合函數(shù)的場(chǎng)所,例如:select user_type, count(*) as count from `user` group by user_type這種類型查詢的時(shí)候,MapHandler方式不起作用,as列都變成key為空串的K-V對(duì),導(dǎo)致有許多地方使用map.get("")代碼的情況出現(xiàn),這種寫法當(dāng)然是不太好的,容易出問題。
鑒于前面沒有時(shí)間了解,就都粗略使用了上面那種粗暴的map.get("")來處理,最好的情況是讓dbutils組件能自動(dòng)識(shí)別到as類型的列名。于是有空了就專門看了看它的源代碼,發(fā)現(xiàn)最主要的一段代碼如下:
所以呢,如果想要dbutils在自動(dòng)轉(zhuǎn)換Map及MapList時(shí)能識(shí)別聚合函數(shù)的列名,那么最好的做法就是重載這種方式,懶一點(diǎn)的,你就干脆修改上面那段代碼,讓它判斷是否使用了as關(guān)鍵字。個(gè)人暫時(shí)搞不清楚官方為什么沒有考慮這一步,有時(shí)間再思考一下!
剛進(jìn)場(chǎng)的時(shí)候戲就落幕
鑒于前面沒有時(shí)間了解,就都粗略使用了上面那種粗暴的map.get("")來處理,最好的情況是讓dbutils組件能自動(dòng)識(shí)別到as類型的列名。于是有空了就專門看了看它的源代碼,發(fā)現(xiàn)最主要的一段代碼如下:
1
public Map<String, Object> toMap(ResultSet rs) throws SQLException {
2
Map<String, Object> result = new CaseInsensitiveHashMap();
3
ResultSetMetaData rsmd = rs.getMetaData();
4
int cols = rsmd.getColumnCount();
5
6
for (int i = 1; i <= cols; i++) {
7
result.put(rsmd.getColumnName(i), rs.getObject(i));
8
}
9
10
return result;
11
}
CaseInsensitiveHashMap是dbutils自定義的一個(gè)Map,忽略鍵大小寫的K-V字典,但是key使用的是ResultSetMetaData.getColumnName(),我想問題大概出在這里,于是認(rèn)真翻了翻java的api文檔(開發(fā)做久了容易遺忘基礎(chǔ)),果然,原來getColumnName()是:獲取指定列的名稱;而as關(guān)鍵字之后,使列名稱變成用于顯示的意義,這個(gè)時(shí)候應(yīng)該使用getColumnLabel():獲取用于打印輸出和顯示的指定列的建議標(biāo)題。建議標(biāo)題通常由 SQL 
2

3

4

5

6

7

8

9

10

11

AS
子句來指定。如果未指定 SQL AS
,則從 getColumnLabel
返回的值將和 getColumnName
方法返回的值相同。自己手動(dòng)試驗(yàn)了一下,果然如所料,問題就出在這里。所以呢,如果想要dbutils在自動(dòng)轉(zhuǎn)換Map及MapList時(shí)能識(shí)別聚合函數(shù)的列名,那么最好的做法就是重載這種方式,懶一點(diǎn)的,你就干脆修改上面那段代碼,讓它判斷是否使用了as關(guān)鍵字。個(gè)人暫時(shí)搞不清楚官方為什么沒有考慮這一步,有時(shí)間再思考一下!
剛進(jìn)場(chǎng)的時(shí)候戲就落幕