我上篇文章分析了JdbcTemplate中各種回調類的使用,但是,我們平常用JdbcTemplate最多的還是query()方法和queryForObject()方法。同樣,其中還有一個使用最多的是BeanPropertyRowMapper。
但是,在JdbcTemplate.queryForObject()中有一個很不起眼的坑,BeanPropertyRowMapper中也一樣。
坑一:BeanPropertyRowMapper的mapRow()
我們在使用BeanPropertyRowMapper時,是給query()方法傳遞一個BeanPropertyRowMapper對象,讓JdbcTemplate幫我們把查詢結果集ResultSet的每一行結果都使用BeanPropertyRowMapper.mapRow()方法,轉化成我們想要的Java類對象。從BeanPropertyRowMapper名稱上也能夠看出來,它是用來映射Java對象的屬性和MySQL表的字段名稱的。但是,在映射的過程中,如果不注意Java對象的屬性名的規範,很可能就得不到我們想要的結果。
先來看一下,在創建BeanPropertyRowMapper對象時,會調用其中的initialize方法,我們看一下initialize方法的具體實現。
如圖,
首選,說一下mappedFields,mapperFields是一個HashMap,用來匹配Java對象的屬性和MySQL表的字段名的。mapperFields中存放所有可能與MySQL表的字段名映射上的那些Java屬性名字。
如紅色框框的第一行,在initialize方法中,BeanPropertyRowMapper會把傳入的泛型Java類的所有屬性名稱的全小寫形式放入mapperFields中,
第二行,把Java類的屬性名轉化成下劃線分割的形式,如myName會被轉化成my_name,這是因為,數據庫在設計字段名稱的時候,一般都會使用下劃線分割形式,也就是my_name。
重點(敲黑板)
所以,如果在使用時,Java類名稱要想和數據庫字段名稱匹配上,必須要把數據庫字段名稱設計成以下兩種中的一種,
數據庫字段名設計成全小寫的形式,如myname;
數據庫字段名設計成下劃線分割的形式,如my_name;
同時,Java屬性名稱應該儘量遵循Java編碼風格,使用camelCase風格,如myName。
坑二:JdbcTemplate.queryForObject()
在使用queryForObject()方法時,我們一般是希望返回一個對象,而不是像query()方法一樣返回一個列表。
但是,如果ResultSet結果集是空的話,queryForObject會拋出異常;如果ResultSet結果集的大小大於1的話,queryForObject也會拋出異常。
查看一下queryForObject源碼:
其實,queryForObject使用的是一個SingleColumnRowMapper對象,其中,第二個queryForObject方法會調用第一個queryForObject方法,坑就在DataAccessUtils.requiredSingleResult(results)裡面。
看一下DataAccessUtils.requiredSingleResult(results)源碼:
如圖所示,如果結果集為空,或者結果集的數量大於1,都會拋出異常,導致queryForObject()無法返回期望結果。
重點(敲黑板)
在我們想查找出一個對象時,應該使用query()方法,如果返回結果不為空,那麼取其中的第一個結果就好了。一般不要使用queryForObject方法,queryForObject會要求符合條件的數據庫結果集有且僅有一條記錄,記錄不存在或者記錄數大於1都會拋出異常。
喜歡的可以關注我,每天都有原創高質量文章發出!