Mybatis中Oracle和Mysql的Count字段問題
我們在進行項目開發時經常會碰到查詢總數的問題,所以我們直接是用select count(1) from table
來進行查詢。那麼在Mybatis通常情況下我們是這麼寫的
<select id="testCount" resultType="int">
select count(1) as "totalCount" from ams.t_ams_ac_pmt_dtl
</select>
這樣做是沒問題的,無論是在Oracle還是Mysql,因爲Mybatis中有類型處理器,當其檢測到resultType時會將其值轉化爲Int類型的值。所以接收是沒問題的。但是如果是如下的寫法的話,將resultType變爲Map,那麼就會有問題。
<select id="testCount" resultType="Map">
select count(1) as "totalCount" from ams.t_ams_ac_pmt_dtl
</select>
在Mybatis中如果resultType是Map的話,那麼在接收結果參數的時候會實例化一個Map<String,Object>
的Map,問題就出現在這,在之前的代碼中是用Map<String,BigDecimal>
來接收的,這在Oracle中是沒有問題的,因爲在Oracle中count函數獲得的值在Java對應的類型是BigDecimal,但是在Mysql中就會出現問題。
此處說明解決問題的能力,實在太強,想要變強,還是需要靜心分析,底層問題到底出在哪
在ResultSetMetaData.getClassNameForJavaType()
的方法中可以看到Mysql字段對應的Java字段,我們可以得知在Mysql中查詢的count得到的數據庫類型是BigInt類型的對應的Java類型是Long
解決辦法
- 改代碼,將接收的
Map<String, BigDecimal>
改爲Map<String, Object>
,然後進行類型轉換 - 改Sql
- 我們可以看到在Mysql中的Decimal和Numeric類型的都被轉化爲了BigDecimal,所以在Sql文件中進行類型轉換就行
select CAST(count(1) as decimal(18,0)) as "totalCount" from table
注意: 如果在查詢時,將表字段和count(id)全部查出來,需要在java實體類中寫一個字段如total,並用@Transient來標註,並且添加get和set方法。
示例sql寫法:
<select id="selectWithFactors" parameterType="com.unicom.udme.dgp.entity.TurnOverRecord" resultMap="BaseResultMap">
select
turn_over_id, turn_over_task, operator_time, complete_time, status,turn_over_type, batch,
turn_over_person, take_over_person, CAST(count(turn_over_id) as decimal(18,0)) as 'total'
from turn_over_record
<where>
1=1
<if test="status == '1'.toString()">
/*查詢userId轉出的記錄*/
and status in ('1', '2', '3')
and turn_over_person=#{turnOverPerson,jdbcType=BIGINT}
</if>
<if test="status == '2'.toString()">
/*查詢userId接收的記錄 ,1:待處理,2:已接收, 3:拒絕*/
and status in ('1','2','3')
and take_over_person=#{takeOverPerson,jdbcType=BIGINT}
</if>
</where>
group by batch
</select>