• 前言

    环境配置

    什么是TypeHandler?

    public interface TypeHandler<T> {
      //设置参数,java类型转换为jdbc类型
      void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
      //将查询的结果转换为java类型
      T getResult(ResultSet rs, String columnName) throws SQLException;
    
      T getResult(ResultSet rs, int columnIndex) throws SQLException;
    
      T getResult(CallableStatement cs, int columnIndex) throws SQLException;
    }
    

    如何自定义并使用TypeHandler?

    如何自定义?

    @MappedJdbcTypes(JdbcType.INTEGER)
    @MappedTypes(String.class)
    public class GenderTypeHandler extends BaseTypeHandler {
    
        //设置参数,这里将Java的String类型转换为JDBC的Integer类型
        @Override
        public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
            ps.setInt(i, StringUtils.equals(parameter.toString(),"男")?1:2);
        }
    
        //以下三个参数都是将查询的结果转换
        @Override
        public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
            return rs.getInt(columnName)==1?"男":"女";
        }
    
        @Override
        public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
            return rs.getInt(columnIndex)==1?"男":"女";
        }
    
        @Override
        public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
            return cs.getInt(columnIndex)==1?"男":"女";
        }
    }
    

    如何将其添加到Mybatis中?

    ## 设置自定义的Typehandler所在的包,启动的时候会自动扫描配置到Mybatis中
    mybatis.type-handlers-package=cn.cb.demo.typehandler
    
    @Bean("sqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource(dataSource);
            sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATOIN));
            org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
            // 自动将数据库中的下划线转换为驼峰格式
            configuration.setMapUnderscoreToCamelCase(true);
            configuration.setDefaultFetchSize(100);
            configuration.setDefaultStatementTimeout(30);
            sqlSessionFactoryBean.setConfiguration(configuration);
            //将typehandler注册到mybatis
            GenderTypeHandler genderTypeHandler = new GenderTypeHandler();
            TypeHandler[] typeHandlers=new TypeHandler[]{genderTypeHandler};
            sqlSessionFactoryBean.setTypeHandlers(typeHandlers);
            return sqlSessionFactoryBean.getObject();
        }
    

    XML文件中如何指定TypeHandler?

    <insert id="insertUser">
            insert into user_info(user_id,his_id,name,gender,password,create_time)
            values(#{userId,jdbcType=VARCHAR},#{hisId,jdbcType=VARCHAR},#{name,jdbcType=VARCHAR},
            #{gender,jdbcType=INTEGER,typeHandler=cn.cb.demo.typehandler.GenderTypeHandler},#{password,jdbcType=VARCHAR},now())
        </insert>
    
    <resultMap id="userResultMap" type="cn.cb.demo.domain.UserInfo">
            <id column="id" property="id"/>
            <result column="user_id" property="userId"/>
            <result column="his_id" property="hisId"/>
                <!-- 指定typeHandler属性为全类名-->
            <result column="gender" property="gender" typeHandler="cn.cb.demo.typehandler.GenderTypeHandler"/>
            <result column="name" property="name"/>
            <result column="password" property="password"/>
        </resultMap>
    
        <select id="selectList" resultMap="userResultMap">
            select * from user_info where status=1
            and user_id in
            <foreach collection="userIds" item="item" open="(" separator="," close=")" >
                #{item}
            </foreach>
        </select>
    

    源码中如何执行TypeHandler?

    入参如何转换?

     @Override
      public void parameterize(Statement statement) throws SQLException {
        //实际调用的是DefaultParameterHandler
        parameterHandler.setParameters((PreparedStatement) statement);
      }
    
    public void setParameters(PreparedStatement ps) {
        ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
        //获取参数映射
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        //遍历参数映射,一一设置
        if (parameterMappings != null) {
          for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            if (parameterMapping.getMode() != ParameterMode.OUT) {
              Object value;
              String propertyName = parameterMapping.getProperty();
              if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
                value = boundSql.getAdditionalParameter(propertyName);
              } else if (parameterObject == null) {
                value = null;
              } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                value = parameterObject;
              } else {
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                value = metaObject.getValue(propertyName);
              }
              //获取类型处理器,如果不存在,使用默认的
              TypeHandler typeHandler = parameterMapping.getTypeHandler();    
              //JdbcType
              JdbcType jdbcType = parameterMapping.getJdbcType();
              if (value == null && jdbcType == null) {
                jdbcType = configuration.getJdbcTypeForNull();
              }
              try {
                //调用类型处理器中的方法设置参数,将Java类型转换为JDBC类型
                typeHandler.setParameter(ps, i + 1, value, jdbcType);
              } catch (TypeException e) {
                throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
              } catch (SQLException e) {
                throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
              }
            }
          }
        }
      }
    

    结果如何转换?

    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        //执行SQL
        ps.execute();
        //处理结果
        return resultSetHandler.handleResultSets(ps);
      }
    
    private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
          throws SQLException {
        if (propertyMapping.getNestedQueryId() != null) {
          return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
        } else if (propertyMapping.getResultSet() != null) {
          addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?
          return DEFERRED;
        } else {
          final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
          final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
          //执行typeHandler中的方法获取结果并且转换为对应的Java类型
          return typeHandler.getResult(rs, column);
        }
      }
    

    总结

    总结

    09-16 20:47