• SqlSessionFactory类的用法
  • 发布于 2个月前
  • 264 热度
    0 评论
SqlSessionFactory 是 MyBatis 的核心类,从这类名可以看出这是个 SqlSession 工厂类,其最重要的功能就是提供创建 MyBatis 的核心接口 SqlSession,所以需要先创建 SqlSessionFactory,为此需要提供配置文件和相关参数。MyBatis 采用构造模式去创建 SqlSessionFactory,可以通过 SqlSessionFactoryBuild 去创建。构建分两步。

构建SqlSessionFactory
第一步,通过 org.apache.ibatis.builder.xml.XMLConfigBuilder 解析配置 XML 文件,读出配置参数,并将读取的数据存入 org.apache.ibatis.session.Configuration 类中。
注意:MyBatis 几乎所有的配置都存在这里。

第二步,使用 Configuration 对象去创建 SqlSessionFactory。SqlSessionFactory 是个接口,而不是实现类,MyBatis 提供了一个默认的实现类 org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
注意:在大部分情况下我们都没必要自己去创建新的 SqlSessionFactory 的实现类。

SqlSessionFactory创建方式是一种 Builder模式。对于复杂的对象而言,直接使用构造方法创建会有些困难,这会导致大量逻辑放在构造方法 ,由于对象的复杂性,在构建的时候更希望一步步有秩序的构建它,从而降低其复杂性。这时候使用一个参数总领全局,例如 Configuration 类,然后分步构建。

MyBatis 提供了创建 SqlSession 的静态工具类 org.apache.ibatis.session.SqlSessionManager,继承了SqlSessionFactory 接口 ,提供了一系列的 newInstance 静态方法用于 创建 SqlSessionFactory 。

构建SqlSessionFactory源码:
public class SqlSessionFactoryBuilder {

  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
     // 堆代码 duidaima.com
      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 {
        if (reader != null) {
          reader.close();
        }
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
}

public class XMLConfigBuilder extends BaseBuilder {

  private boolean parsed;
  private final XPathParser parser;
  private String environment;
  private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
  //省略.....
  private XMLConfigBuilder(Class<? extends Configuration> configClass, XPathParser parser, String environment,
      Properties props) {
    super(newConfig(configClass));
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }
  private static Configuration newConfig(Class<? extends Configuration> configClass) {
    try {
      // 反射创建对象
      return configClass.getDeclaredConstructor().newInstance();
    } catch (Exception ex) {
      throw new BuilderException("Failed to create a new Configuration instance.", ex);
    }
  }
}
构建 Configuration
构建 SqlSessionFactory 中,Configuration 是最重要的,它的作用如下:
1.读入配置文件,包括基础配置 XML 文件和映射器的 XML 文件。
2.初始化基础配置,比如 MyBatis 别名等,一些重要的类对象,例如,插件,映射器, ObjectFactory 和 typeHandler 对象。
3.提供单例,为后续创建 SessionFactory 服务并提供配置的参数。

4.执行一些重要的对象方法,初始化配置信息。


Configuration 是通过 XMLConfigBuilder 构建的。MyBatis 会读出所有 XML 配置的信息。然后,将这些信息保存到 Configuration 类的单例中。它会做如下初始化:
properties 全局参数
settings 设置
typeAliases 别名
typeHandler 类型处理器
ObjectFactory 对象
Plugin 插件
environment 环境
DatabaseIdProvider 数据库标识

Mapper 映射器


映射器的内部组成
一般而言,一个映射器是由 3 个部分组成:
MappedStatement,它保存映射器的一个节点(select | insert | delete | update)。包括许多我们配置的 SQL,SQL 的 id,缓存信息,resultMap,parameterMap,resultType,languangeDriver等重要配置内容。
SqlSource,它是提供 BoundSql对象的地方,它是 MappedStatement 的一个属性。

BoundSql,它是建立 SQL 和参数的地方。它有 3 个常用的属性: SQL,parameterObject,parameterMappings。


MappedStatement 对象涉及的东西较多,一般都不会修改它,因为容易产生不必要的错误。
SqlSource 是一个接口,它主要作用是根据参数和其他的规则组装 SQL,也比较复杂,一般也不需要修改它。
BoundSql ,对于参数和 SQL 而言,主要的规则反映在 BoundSql 类对象上,在插件中往往需要拿到它进而拿到当前运行的 SQL 和参数以及参数规则,做出适当的修改,来满足我们特殊的需求。

BoundSql 会提供 3 个主要属性: parameterMappings,parameterObject 和 sql。
parameterObject ,为参数本身,可以传递简单对象,POJO,Map,或者 @Param 注解的参数,在插件中常用到。传递简单对象(包括 int,String,float,double等),MyBatis 会把参数变为 Integer 对象传递,类似的 long,String,float,double也是如此。传递的是 POJO 或 Map,parameterObject 就是传入的 POJO 或 Map 不变。

也可以传递多个参数,如果没有 @Param 注解,那么 MyBatis 就会把 parameterObject 变为一个 Map<String, Object> 对象,其键值的关系是按顺序来规划的,类似于这样的形式
{
    "1":p1,
    "2":p2,
    "3":p3,
    ....
    "param1":p1,
    "param2":p2,
    "param3":p3
}
所以在编写的时候,可以使用 #{param1} 或 #{1} 去引用第一个参数。

如果使用 @Param 注解,那么 MyBatis 就会把 parameterObject 变为一个 Map<String, Object> 对象,类似于没有 @Param 注解,只是把其数字的键值对应置换为了 @Param 注解的键值。比如注解 @Param("key1") String p1。
{
    "key1":p1
}
parameterMappings,它是一个 List,每一个元素都是 ParameterMapping 的对象。这个对象会描述我们的参数,包括属性,名称,表达式,javaType,jdbcType,typeHandler 等重要信息。一般不需要改变它。

通过它可以实现参数和 SQL 的结合,以便 PreparedStatement 能够通过它找到 parameterObject 对象的属性并设置参数,使得程序准确运行。sql 属性就是我们书写在映射器里面的一条 SQL,在大多数时候无需修改它,只有在插件的情况下,可以根据需要进行改写,但一定要谨慎行事。
用户评论