zoukankan      html  css  js  c++  java
  • 对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中可以不写,自动匹配

  • 相关阅读:
    .NET版UEditor报请求后台配置项http错误,上传功能无法使用的错误解决
    [Asp.net mvc]Asp.net mvc 中使用LocalStorage
    Asp.net mvc Kendo UI Grid的使用(三)
    [Asp.net mvc]Asp.net mvc 使用Json传递数据
    Asp.net mvc Kendo UI Grid的使用(二)
    接口
    结构
    多态
    继承
    方法
  • 原文地址:https://www.cnblogs.com/qunan/p/9213944.html
Copyright © 2011-2022 走看看