對mybatis的Handler 從使用角度介紹


最近在開發中,涉及到了講數據庫查詢的類型,直接轉為java需要的類型。 由於對handler 理解不到位 和 使用不當。躺了一些坑。

主要涉及的有2種。

1、varchar 轉 List<T>

2、varchar 轉Map<T>

如圖是寫的兩個handler。 

 ListTypeHandler 為了保證 handler的通用性,采取了 將mybatis xml 配置中的type,傳入 ListTypeHandler 中直接使用。 后來發現這是個大坑。
public class ListTypeHandler<E> extends BaseTypeHandler<List<E>> {
    
    private Class<E> type;

    public ListTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.type = type;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, List<E> parameter, JdbcType jdbcType) throws SQLException {
        String x = JSON.toJSONString(parameter);
        ps.setString(i, x);
    }

    @Override
    public List<E> getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String s = rs.getString(columnName);
        return StringUtils.isBlank(s) ? null : JSON.parseArray(s, type);
    }

    @Override
    public List<E> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String s = rs.getString(columnIndex);
        return StringUtils.isBlank(s) ? null : JSON.parseArray(s, type);
    }

    @Override
    public List<E> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String s = cs.getString(columnIndex);
        return StringUtils.isBlank(s) ? null : JSON.parseArray(s, type);
    }

}
public class MapTypeHandler extends BaseTypeHandler<Map<String, Object>> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Map<String, Object> parameter, JdbcType jdbcType) throws SQLException {
        if(MapUtils.isNotEmpty(parameter)) {
            String x = JSON.toJSONString(parameter);
            ps.setString(i, x);
        }else{
            ps.setString(i, null);
        }
    }

    @Override
    public Map<String, Object> getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String s = rs.getString(columnName);
        return StringUtils.isBlank(s) ? null : JSON.parseObject(s, new TypeReference<Map<String, Object>>(){}); // JSON.parseObject(s, getRawType());
    }

    @Override
    public Map<String, Object> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String s = rs.getString(columnIndex);
        return StringUtils.isBlank(s) ? null : JSON.parseObject(s, new TypeReference<Map<String, Object>>(){}); 
    }

    @Override
    public Map<String, Object> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String s = cs.getString(columnIndex);
        return StringUtils.isBlank(s) ? null : JSON.parseObject(s, new TypeReference<Map<String, Object>>(){}); 
    }

}

 首先沒有在mybatis.xml  總注冊,直接通過@result指定使用

    @Select("<script>SELECT " + SELECT_FILEDS_AS + " FROM " + TABLE + " WHERE valid =1 and config_id = #{configId} " + SELECT_LIMIT + " </script>")
    @Results(value={
            @Result(column="operation_content", property="operationContent", javaType=String.class, jdbcType=JdbcType.VARCHAR,typeHandler=ListTypeHandler.class),
    })
    List<OperateRecord> selectList(@Param("configId") long configId,@Param("offset") int offset,@Param("limit") int limit);

 

由於希望 ListTypeHandler 可以通用一點,因此采用了傳入的javaType 即String,使用, 這個時候查詢也沒問題。感覺還很完美。

接下來,開始寫插入

  @Insert({"INSERT INTO " + TABLE + " (config_id, operation_staff, operation_time, action, operation_content, ctime,valid) values "
            +"( #{configId}, #{operationStaff}, #{operationTime}, #{action}, #{operationContent, javaType=String, jdbcType=VARCHAR,typeHandler=ListTypeHandler}, unix_timestamp(),1 )"})
    int insert(OperateRecord record);

 

這個時候就開始各種報錯,最后經過一頓百度,發現是沒有注冊,於是增加注冊。

<typeHandlers>
        <typeHandler handler="com.support.ListTypeHandler" javaType="List" jdbcType="VARCHAR" />
    </typeHandlers>

 

這個時候,在插入,發現成功了。 這個時候,認為全部搞定了,開始部署線下,進行聯調。結果最大的問題才剛剛開始。

后頭測試查詢的時候,發現查詢又報錯。。。 於是開始debug,發現 'name' 類型varchar,java類型 String。 也開始進入list轉換。 一臉懵逼。

於是嘗試性的去掉字段的別名,發現居然成功了。。。

然后開始進入另一個大坑。認為和別名有關。

進入下一步的嘗試

 @Result(column = "initiateName" ,property = "initiateName")

 

為字段指定result,發現問題完美解決。 

這個時候,任務只要@Results(value={}),使用過handler的,其他字段就也要指定。

這個時候,終於認為大功告成,結果。。。。

測試另一個dao的時候,發現,這個dao完全沒有使用handler, 查詢結果中的字段,也會去轉換。。

然后,又開始懵逼。。。 一頓百度,最終恍然大悟。 再mybatisxml配置之后,是全局匹配。

因為不能使用傳入的java類型, 再listhandler寫死。

結論:

1.查詢時候,不需要注冊,即可直接通過result使用。type指定也可以生效。

2.插入的時候必須注冊。

3.注冊后,通過java,jdbc類型,還有名字全局匹配

4.result中可以不寫,自動匹配

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM