Mybatis源码部分理解-类型装换

发布于:2022-12-10 ⋅ 阅读:(801) ⋅ 点赞:(0)

                Mybatis框架的原理介绍

        ​​​​​​

一、什么是MyBatis?

是一款优秀的持久层框架,支持动态Sql相比JDBC,减少很多代码,不需要开关连接,只需要修改sql语句。

mybatis优缺点:
1.简单易学,会点Java基础Mysql就可以使用
2.相比JDBC,减少很多代码,不需要开关连接,只需要修改sql语句.
3.很好的与数据库兼容mysql

一、MyBatis怎么初始化?

SqlSessionFactoryBuilder.build(InputStream inputStream, String environment,Properties properties) 用来创建项目,使用解析器,会话工厂等 源码:


/**
 * Builds {@link SqlSession} instances.
 *
 * @author Clinton Begin
 */
public class SqlSessionFactoryBuilder {

  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }

  public SqlSessionFactory build(Reader reader, String environment) {
    return build(reader, environment, null);
  }

  public SqlSessionFactory build(Reader reader, Properties properties) {
    return build(reader, null, properties);
  }

  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

  public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment) {
    return build(inputStream, environment, null);
  }

  public SqlSessionFactory build(InputStream inputStream, Properties properties) {
    return build(inputStream, null, properties);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

}

XMLConfigBuilder.parseConfiguration(XNode root)解析核心配置,赋值给configuration对象

SqlSourceBuilder类是如何解析获取sql语句的

public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
    // 对#{}这样的字符串内容的解析处理类
    ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
    GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
    // 获取真实的可执行性的sql语句
    String sql = parser.parse(originalSql);
    // 包装成StaticSqlSource返回
    return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
  }

mybatis源码类型装换

TypeHandler
TypeHandler是类型处理器接口,MyBatis中所有的类型转换器都继承了TypeHandler接口,在TypeHandler接口中定义了如下四个方法,这四个方法分为两类:setParameter()方法负责将数据由JdbeType类型转换成Java类型;getResult()方法及其重载负责将数据由Java类型转换成JdbcType类型。
 

public interface TypeHandler<T> {

  //在通过PreparedStatement为SQL语句绑定参数时,会将数据由JdbcType类型转换成Java类型
  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  //从 ResultSet 中获取数据时会调用此方法,会将数据由Java类型转换成JdbcType类型
  T getResult(ResultSet rs, String columnName) throws SQLException;

  T getResult(ResultSet rs, int columnIndex) throws SQLException;

  T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}

BaseTypeHandler中实现TypeHandler.setParameter()方法和TypeHandler.getResult()方法, 具体实现如下所示。需要注意的是,这两个方法对于非空数据的处理都交给了子类实现。

public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
  if (parameter == null) {
    if (jdbcType == null) {
      //参数 类型 异常
      throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
    }
    try {
      //绑定参数为null的处理
      ps.setNull(i, jdbcType.TYPE_CODE);
    } catch (SQLException e) {
      throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
            + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
            + "Cause: " + e, e);
    }
  } else {
    try {
      //绑定非空参数 该方法为抽象方法 由子类实现
      setNonNullParameter(ps, i, parameter, jdbcType);
    } catch (Exception e) {
      throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
            + "Try setting a different JdbcType for this parameter or a different configuration property. "
            + "Cause: " + e, e);
    }
  }
}

public T getResult(ResultSet rs, String columnName) throws SQLException {
  try {
    //抽象方法 由多个重载 由子类实现
    return getNullableResult(rs, columnName);
  } catch (Exception e) {
    throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + e, e);
  }
}

BaseTypeHandler的实现类比较多,如图所示,但大多是直接调用PreparedStatementResultSetCallableStatement的对应方法,实现比较简单。

这里以IntegerTypeHandler为例简单介绍,其他的实现类请读者参考相关
 

public class IntegerTypeHandler extends BaseTypeHandler<Integer> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
      throws SQLException {
    //调用PreparedStatement.setInt()实现参数绑定
    ps.setInt(i, parameter);
  }

  @Override
  public Integer getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    //调用PreparedStatement.getInt()获取指定列值
    int result = rs.getInt(columnName);
    return result == 0 && rs.wasNull() ? null : result;
  }

  @Override
  public Integer getNullableResult(ResultSet rs, int columnIndex)
      throws SQLException {
    //调用ResultSet.getInt()获取指定列值
    int result = rs.getInt(columnIndex);
    return result == 0 && rs.wasNull() ? null : result;
  }

  @Override
  public Integer getNullableResult(CallableStatement cs, int columnIndex)
      throws SQLException {
    //调用CallableStatement.getInt()获取指定列值
    int result = cs.getInt(columnIndex);
    return result == 0 && cs.wasNull() ? null : result;
  }
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到