欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Mybatis源码解析

程序员文章站 2022-03-02 15:20:55
...

Mybatis源码解析

查询测试Demo

/**
 * 获取SqlSessionFactory对象
 *
 * @return
 * @throws IOException
 */
private SqlSessionFactory getSqlSessionFactory() throws IOException {
    return new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
}
@Test
public void testQuery() throws IOException {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee empById = employeeMapper.getEmpById(2);
        System.out.println(empById);
        System.out.println(empById.getDept());
        sqlSession.commit();
    } catch (Exception e) {
    	e.printStackTrace();
    } finally {
    	sqlSession.close();
    }
}

获取SqlSessionFactory

  1. 创建XMLConfigBuilder实例,解析mybatis全局配置文件及所有SQL映射文件

    调用构造器创建XMLConfigBuilder实例时,在构造器中调用Configuration的无参构造器创建了一个Configuration对象作为自己的属性

  2. 解析mybatis全局配置文件

    解析settings、typeAliases、mappers、… 标签,并将信息封装到XMLConfigBuilder实例的Configuration对象属性中。

  3. 解析SQL映射文件

    即第2步中的解析mappers标签的核心流程

    1. 创建XMLMapperBuilder实例,解析SQL映射文件

      从mappers标签中解析出mapper映射文件的路径,创建流并创建XMLMapperBuilder实例

    2. 解析cache、cache-ref、select、update、delete、insert、… 标签

      针对select、update、delete、insert标签,解析标签中的每一个属性及标签体中的sql(包括解析动态sql),封装为一个MappedStatement对象,添加到configuration对象的mappedStatements(Map)中。

  4. 创建SqlSessionFactory实现类对象并返回

    利用XMLConfigBuilder实例、XMLMapperBuilder实例解析完mybatis全局配置文件以及SQL映射文件之后,返回XMLConfigBuilder实例中的Configuration对象,利用返回的Configuration对象,作为DefaultSqlSessionFactory的构造器参数,创建DefaultSqlSessionFactory对象返回。

获取SqlSession

  1. 调用SqlSessionFactory实例的openSession方法

    1. 通过SqlSessionFactory实例中的Configuration对象,获取当中的DataSource信息开启事务,创建并返回一个Transaction对象。

      这里开启事务是指逻辑上的开启事务,Transaction对象中的并没有数据库连接,仅仅是设置了Transaction对象的autoCommit属性值为false。

    2. 利用Configuration对象创建Executor

      根据ExecutorType创建对应的Executor,该Executor中初始化了一个本地缓存PerpetualCache,并封装了上一步中创建的事务对象。若还配置了二级缓存,则会将用CachingExecutor包装刚创建的Executor

    3. 调用拦截器链的pluginAll方法包装Executor

      executor = (Executor) interceptorChain.pluginAll(executor);

  2. 创建DefaultSqlSession对象并返回

    DefaultSqlSession对象封装了Configuration对象以及步骤1中创建的Executor

获取Mapper

  1. 调用SqlSession对象的getMapper方法,传入对应Mapper的Class对象。

  2. 调用Configuration对象的getMapper方法。

  3. 调用MapperRegistry对象的getMapper方法,利用动态代理创建了一个Mapper代理实例并返回。

    MapperRegistry中获取了一个Mapper代理工厂MapperProxyFactory,通过代理工厂,利用动态代理技术创建了一个Mapper代理实例并返回。

// 1 ---- TestCase
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
// 2 ---- DefaultSqlSession
public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
}
// 3 ---- Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}
// 4 ---- MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    return mapperProxyFactory.newInstance(sqlSession);
}
// 5 ---- MapperRegistry
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

执行查询

  1. Method对象包装成MapperMethod对象

    上一步获取Mapper的时候,得到的是一个mapper代理对象,在调用代理对象方法的时候,会先把Method对象包装成MapperMethod对象,然后调用其execute方法。

  2. 执行查询

    1. 判断要操作的类型,调用SqlSession对象的查询方法

    2. 获取当前操作对应的Sql信息

      这里先获取与当前操作对应的MappedStatement对象,该对象在获取SqlSessionFactory的时候,就已经通过解析对应的Mapper映射文件创建了出来,一个MappedStatement对象封装一个select|update|delete|insert语句信息。然后把查询参数与MappedStatement对象中Sql信息绑定到一起并返回BoundSql对象。

    3. 生成CacheKey对象

    4. 若配置了二级缓存,则拿CacheKey对象去二级缓存中查询,查询到则直接返回

    5. 若在二级缓存中没查到,再拿CacheKey对象从一级缓存中查找,查询到则直接返回

    6. 若在一级缓存中也没查到,则从数据库查询。查询到之后,先把结果放进一级缓存,然后在放进二级缓存,键都是CacheKey对象,最后返回。

相关标签: mybatis