• 第四篇 mybatis的运行原理(1):重要组件的介绍


    一、组件介绍

    相比其他框架,mybatis的组件构成还是相对简单的,下面是网络上比较常见的一张图,关于mybatis的执行流程,其中是mybatis的最常用的组件:


      在来学习mybatis的源码和底层原理之前,先来了解各大组件的作用和生命周期:
        (1)SqlSessionFactoryBuilder
                      SqlSessionFactoryBuilder是利用XML或者Java编码获得资源来构建SqlSessionFactory的,通过它可以构建多个SqlsessionFactory,它的作用就是一个构建器,一旦创建SqlSessionFactory,
               它的作用就会消失,所以构建SqlsessionFactory成功后会废弃回收。所以的它的生命周期只存在于方法的局部,它的作用就是生成SqlSessionFactory对象。

       (2)SqlSessionFactory对象
                    SqlSessionFactory的作用就是创建SqlSession,Sqlsession相当于JDBC中的Connection对象,每次访问数据库都需要创建SqlSession,前面的文章就已经说过,一个SqlSessionFactory对应一个数据库,
               那么能不能多个对应一个数据库了?是可以的,但是这样做的话,有多个SqlSessionFactory就会有很多的数据库连接,这样会导致数据库连接资源容易耗尽,且不易管理数据库连接,所以,mybatis的设计采用的单例
               模式,这样可以更有效的管理数据库的资源分配。由于SqlSessionFactory一直维护着SqlSession的创建,所以SqlSessionFactory的生命周期是框架运行的整个过程。

       (3)SqlSession
                   SqlSession对象时连接数据库的通道,更准确地说是访问数据库的一次会话,当发起访问数据库的请求时,创建一个SqlSession对象,请求完成关闭SqlSession。  要注意的是,SqlSession是一个线程不安全的对象,
             在涉及多线程的时候,要保证操作数据库的隔离级别 、数据库锁等高级特性,此外,SqlSession使用完成后都必须及时的关闭,避免占用连接资源,导致数据库宕机

    (4)Mapper
                   Mapper是一个接口,它的作用是发送SQL,当然,作为接口,当然不能执行SQL, 所以Mapper是代理方式完成这一操作, 然后返回我们需要的结果,或者执行SQL从而修改数据库的数据,具体实现,后面会说。
            因此,Mapper是一个方法级别的东西,当SqlSession销毁时,Mapper也会随之销毁。

    二、SqlSessionFactory的创建

           前面已经知道了mybatis的使用,执行流程以及重要的组件构成,但是对于一名开发者来说,知道这些远远不够,学习mybatis的底层原理,可以帮我们更好解决框架使用中的问题,甚至可以修改框架或者自定义插件来满足我们的业务需求。
     所以我们从源码层面一步一步走mybatis的执行流程。 首先,从mybatis加载解析mybatis的配置文件mybatisConfig.xml开始。我们先来看看我们是如何创建SqlSessionFactory的:

      /*资源*/
       InputStream is = UserService.class.getClassLoader().getResourceAsStream("mybatis/mybatisConfig.xml")
       /*创建SqlSessionFactory*/
       SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

    由上述代码可以看出SqlSessionFactory的创建是依托于SqlSessionFactoryBuilder类的build方法,打开该类SqlSessionFactoryBuilder由众多形式的build方法组成,尽管方法有很多,但是目的只有一个那就是

    解析资源,创建SqlSessionFactory,所以我们以public SqlSessionFactory build(InputStream inputStream)为例深入

       public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
            try {
              /*解析xml文件,封装成一个XMLConfigBuilder对象*/
              XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
              /*生成一个参数类Configuration对象,然后通过该参数类创建DefaultSqlSessionFactory对象*/
              Configuration config = parser.parse();
              return build(config);
            } 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);
          }
    
        }

    java对于xml文件资源的解析有dom解析,sax解析,dom4j解析,mybatis使用的dom方式,具体xml会在别的文章中说到,xml解析会得到一个  XMLConfigBuilder对象,

    之后,XMLConfigBuilder对象会通过parse方法初始为一个Configuration对象,看看Configuration对象的内部,

    public class Configuration {
    
      protected Environment environment;
    
      protected boolean safeRowBoundsEnabled = false;
      protected boolean safeResultHandlerEnabled = true;
      protected boolean mapUnderscoreToCamelCase = false;
      protected boolean aggressiveLazyLoading = true;
      protected boolean multipleResultSetsEnabled = true;
      protected boolean useGeneratedKeys = false;
      protected boolean useColumnLabel = true;
      protected boolean cacheEnabled = true;
      protected boolean callSettersOnNulls = false;
      protected String logPrefix;
      protected Class <? extends Log> logImpl;
      protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
      protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
      protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
      protected Integer defaultStatementTimeout;
      protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
      protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
    .....
    .....

    从熟悉的变量名就可以联想到这个对象就是xml文件里对mybatis配置属性,那为什么这些属性不直接放到DefaultSqlSessionFactory类里面去了,这主要是由于创建SqlSessionFactory

    需要的参数复杂,如果直接放到类的构造方法里面,这会导致大量的逻辑存在于类的构造方法中,所以使用一个参数类总领全局,分步构建,可以有效降低这种逻辑混乱的问题。

    所以Configuration 对象也SqlSessionFactory创建过程中最重要的一个类。甚至mybatis的大多数的配置都是源于Configuration

    Configuration 对象的作用:

        1. 读取配置文件,包括初始化xml和映射器xml

        2. 初始化基础配置,如果xml文件里set和typehandle

        3. 提供单例,生成单例,为之后生成session提供配置

        4. 执行一些重要的对象方法,如构建构造器executor等。
    SqlSessionFactory接口有两个实现类:DefaultSqlSessionFactory类和SqlSessionManager类,但是是使用DefaultSqlSessionFactory创建SqlSessionFactory对象,下一篇将会剖析DefaultSqlSessionFactory具体的创建过程


  • 相关阅读:
    Go语言基础之切片
    Go语言基础之map
    Go语言基础之函数
    Go语言基础之指针
    Go语言基础之结构体
    Redis缓存失效策略
    redis 的过期策略都有哪些?内存淘汰机制都有哪些?
    关于redis的主从、哨兵、集群
    Redis的 RDB和 AOF持久化的区别
    为什么做分布式使用 Redis
  • 原文地址:https://www.cnblogs.com/zhexuejun/p/11233041.html
Copyright © 2020-2023  润新知