Mybatis - Dao接口如何与XML文件的SQL建立关系

853 阅读2分钟

一、概述

  • Mybatis 通过解析 XML 文件,将每一个标签封装成为一个个 MappedStatement,而后在调用的时候,通过动态代理进行实现

二、初始化

  • Mybatis 通过 建筑者 模式进行创建

  • 首先我们要知道每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的,SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。

1、SqlSessionFactory和SqlSessionFactorybean

  • openSession方法是为了获取一个SqlSession对象,完成必要数据库增删改查功能;

  • getConfiguration的配合;来配置mapper映射文件、SQL参数、返回值类型、缓存等属性。


public interface SqlSessionFactory {

  SqlSession openSession();

  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}
  • 日常开发中我们都是将Mybatis与Spring一起使用的,所以把实例化交给Spring处理。

  • org.mybatis.spring.SqlSessionFactoryBean,它实现了InitializingBean接口

  • 这说明,在这个类被实例化之后会调用到afterPropertiesSet()。它只有一个方法

public void afterPropertiesSet() throws Exception { 
    this.sqlSessionFactory = buildSqlSessionFactory(); 
}
  • buildSqlSessionFactory。它可以分为两部分来看:

  • 1、从配置文件的property属性中加载各种组件,解析配置到configuration中

  • 2、加载mapper文件,解析SQL语句,封装成MappedStatement对象,配置到configuration中。

(1) MappedStatement 对象,

  • 存在两个最重要的属性
    • id
      • 全限定类名+方法名组成的ID
    • sqlSource
      • 当前SQL标签对应的SqlSource对象。
  • 将其存放到 Configuration#mappedStatements 对象中,后续可以通过 id 直接索引到 对应的 sqlSource 对象

2、dao 动态代理

(1)包扫描路径

@MapperScan({"com.mmzsblog.business.dao"})

(2)开始扫描

  • 具体在 BeanDefinitionRegistryPostProcessor() 这个类中,去调用 doScan()方法,将会扫描到所有的 Mapper 接口,源码不细讲了,具体自己看

(3)注册 BeanDefinition

  • 将所有扫描到的 Mapper 接口注册成为 BeanDefinition 对象,这样子就可以进行初始化

(4)动态代理

  • 在setSqlSessionFactory这个方法里,sqlSession获取到的是SqlSessionTemplate实例。而在SqlSessionTemplate对象中,主要包含sqlSessionFactory和sqlSessionProxy,而sqlSessionProxy实际上是SqlSession接口的代理对象,实际调用的是代理类的invoke方法。

题外话: 如果我们主动实现了 dao 接口,然后又配置了 mapper 会发生什么? 这时候,在使用 ioc 容器中将会存在两个 dao 接口的实现类,你需要自己指定注入的对象是那个

3、执行

  • 当我们调用Dao接口方法的时候,实际调用到代理对象的invoke方法。 在这里,实际上调用的就是SqlSession里面的东西了
public class DefaultSqlSession implements SqlSession {

	public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
		try {
			MappedStatement ms = configuration.getMappedStatement(statement);
			return executor.query(ms, 
				wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
		}
	}
}

  • 通过statement全限定类型+方法名拿到MappedStatement 对象,然后通过执行器Executor去执行具体SQL并返回。

三、总结

  • SqlSource以及动态标签SqlNode
  • MappedStatement对象
  • Spring 工厂Bean 以及动态代理
  • SqlSession以及执行器

参考: