MyBatis查询报错Error attempting to get column ‘x‘ from result Cause: com.alibaba.fastjson.JSONException

问题分析及解决方案

由于该字段是有单选改为多选,该字段的历史数据的格式不是JSONArray形式,所以导致查询结果类型与实体类中不匹配。
解决方案(建议使用第一种,不影响历史数据):

一、修改该字段的历史数据为JSONArray类型;
update deal_base a set fund_type = concat('["', a.fund_type, '"]');
二、删除该字段的历史数据;

该问题产生的背景

该错误出现的情况:数据表中有一个字段是fund_type,该字段用于存储基金的类型。起初设计的是基金类型单选(下拉单选),后来发现多选更适合,因此就把web页面上的改字段改为了多选,从而导致出现JSONException。

起初是这样的:

单选下拉​​

后来变成这样的:

下拉多选

简述:

就是把下拉单选换成了下拉多选。在这里我把原来的实体类字段属性变成了JSONArray以便将整个数组存入到数据库中。

    /**
     * 基金类型Str
     */
    @ApiModelProperty(value = "基金类型Str", position = 300)
    private String fundTypeStr;

	/**
     * 基金类型
     */
    @ApiModelProperty(value = "基金类型", position = 300)
    private JSONArray fundType;

    public String getFundTypeStr() {
    
    
        return fundTypeStr;
    }

    public void setFundTypeStr(String fundTypeStr) {
    
    
        this.fundTypeStr = fundTypeStr;
    }

    public JSONArray getFundType() {
    
    
        return fundType;
    }

    public void setFundType(JSONArray fundType) {
    
    
        this.fundType = fundType;
    }

在这里有一步很重要,就是需要实现Mybatis的插件,用于String和JSONArray的转换。附插件代码(具体代码及作用网上都是,不赘述):

/**
 * @author Sophia
 *
 * @description 用以mysql中varchar格式的字段,进行转换的自定义转换器,转换为实体类的JSONArray属性
 */
@MappedTypes(JSONArray.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class JsonTypeHandler extends BaseTypeHandler<JSONArray> {
    
    

    /**
     * 重写设置参数
     * @param ps
     * @param i
     * @param parameter
     * @param jdbcType
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, JSONArray parameter, JdbcType jdbcType) throws SQLException {
    
    
        ps.setString(i, String.valueOf(parameter.toJSONString()));
    }

    /**
     * 根据列名,获取可以为空的结果
     * @param rs
     * @param columnName
     * @return
     * @throws SQLException
     */
    @Override
    public JSONArray getNullableResult(ResultSet rs, String columnName) throws SQLException {
    
    
        String sqlJson = rs.getString(columnName);
        if (null != sqlJson){
    
    
            return JSONObject.parseArray(sqlJson);
        }
        return null;
    }

    /**
     * 根据列索引,获取可以为空的结果
     * @param rs
     * @param columnIndex
     * @return
     * @throws SQLException
     */
    @Override
    public JSONArray getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    
    
        String sqlJson = rs.getString(columnIndex);
        if (null != sqlJson){
    
    
            return JSONObject.parseArray(sqlJson);
        }
        return null;
    }

    @Override
    public JSONArray getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    
    
        String sqlJson = cs.getString(columnIndex);
        if (null != sqlJson){
    
    
            return JSONObject.parseArray(sqlJson);
        }
        return null;
    }
}

在dao.xml中也要注意使用自定义的Mybatis插件进行转换(否则会无法正常启动系统)。
在xml文件中,我使用的是resultMap,将JSONArray字段使用自定义插件匹配,如下(根据自己的情况二选一):

	<!--设置别名 column要和别名保持一致-->
    <resultMap id="BaseResultMapJSON" type="com.anxin.deal.warehousing.entity.DealFofWarehousing">
        <result column="fundType" property="fundType" typeHandler="com.anxin.common.mybatis.JsonTypeHandler" />
    </resultMap>
	<!--未设置别名,column要和数据库字段保持一致-->
	    <resultMap id="BaseResultMapJSON" type="com.anxin.deal.warehousing.entity.DealFofWarehousing">
        <result column="fund_type" property="fundType" typeHandler="com.anxin.common.mybatis.JsonTypeHandler" />
    </resultMap>

定义了该resultMap后,要在有fundType的字段的方法返回类型中使用resultMap。如:

<select id="getById" parameterType="String" resultMap="BaseResultMapJSON">
        select 
        id as id,
        name as name,
        deal_type as dealType,
        fund_type as fundType,
        create_time as createTime,
        update_time as updateTime 
        from deal_fof_warehousing
        where  del_flag = '0' and  id = #{id}
    </select>
到此,大功告成!启动测试。

报错
查看日志输出:

10:54:47.967 [http-nio-8088-exec-27] ERROR c.a.f.w.e.GlobalExceptionHandler - [handleException,84] - 错误代码:E380nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'fundType' from result set.  Cause: com.alibaba.fastjson.JSONException: syntax error, expect [, actual error, pos 0, fieldName null
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'fundType' from result set.  Cause: com.alibaba.fastjson.JSONException: syntax error, expect [, actual error, pos 0, fieldName null
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
	at com.sun.proxy.$Proxy120.selectList(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230)
	at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:139)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:76)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
	at com.sun.proxy.$Proxy162.findSonListByDept(Unknown Source)
	at com.anxin.deal.base.service.DealBaseService.findList(DealBaseService.java:474)
	at com.anxin.deal.base.service.DealBaseService$$FastClassBySpringCGLIB$$9ffc5dd9.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)

​报错了: exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'fundType' from result set. Cause: com.alibaba.fastjson.JSONException: syntax error, expect [, actual error, pos 0, fieldName null,

扫描二维码关注公众号,回复: 15435179 查看本文章

从字面意思不难理解是获取到fundType字段的数据错误。

在数据库中查看该字段,发现该字段中有的值不是数组类型(历史数据的问题),所以导致数据获取异常。
报错根本
只需要将不是数据的数据该成数组数据,或将不是数组的数据删除即可完美解决该问题!

希望能帮助各位小伙伴!若有其他更好的方案,可关注评论!

猜你喜欢

转载自blog.csdn.net/qq_42320934/article/details/123371518
今日推荐