Mybatis执行查询过程源码分析

Mybatis的基本构成

核心组件

  • SqlSessionFactoryBuilder(构造器):它会根据配置信息或者代码来生成SqlSessionFactory(工厂接口);
  • SqlSessionFactory:依靠工厂来产生SqlSession会话;
  • SqlSession:是一个既可以发送SQL去执行并返回结果,也可以获取Mapper的接口;
  • SQL Mapper:是一个由Java和XML文件或注解构成的需要给出对应的SQL和映射规则。

看源码

正确方式:宏观>微观>画图

宏观:了解本质,了解这个东西是用来干嘛的;
微观

以查询一条记录为线索;

public class SelectMapper {
    static SqlSessionFactory factory;
    static {
        try {
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            factory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void select(){
        SqlSession sqlSession = factory.openSession();
        Student stu = sqlSession.selectOne("mapper.StudentMapper.select", 1);
        sqlSession.close();
        System.out.println(stu);
    }
}

mybatis初始化的过程,如何获取SqlSessionFactory对象?

  1. 调用SqlSessionFactoryBuilder的build方法,会根据xml配置文件的输入流inputStream等信息创建XMLconfigBuilder对象;
  2. SqlSessionFactoryBuilder调用XMLConfiguration对象的parse方法,这个方法会返回一个Configuration对象;
  3. SqlSessionFactoryBuilder根据Configuration对象创建一个DefaultSessionFactory对象;
  4. 将这个对象返回供Client使用。
/* SqlSessionFactoryBuilder*/
public SqlSessionFactory build(InputStream inputStream) {
        return this.build((InputStream)inputStream, (String)null, (Properties)null);
    }
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
        	//1.创建XMLConfigBuilder对象用来解析XML配置文件,生成Configuration对象
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            //2. parser.parse()将XML配置文件信息解析成Java的Configuration对象
            //3. 根据Configuration对象创建出SqlSessionFactory对象
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

            try {
                inputStream.close();
            } catch (IOException var13) {
                ;
            }
        }
        return var5;
    }    
public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
    }

参考文章:https://blog.csdn.net/u010349169/article/details/37744073
如何将mybatis-config.xml内容映射为Java中的Configuration对象

当SqlSessionFactoryBuilder执行build方法,调用XMLConfigBuilder的parse方法,然后返回Configuration对象。那么parse方法是如何处理XML文件,生成Configuration对象的?

/*SqlSessionFactoryBuilder*/
public SqlSessionFactory build(InputStream inputStream) {
        return this.build((InputStream)inputStream, (String)null, (Properties)null);
    }
    
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
        	//建造xmlConfiguration对象(1)
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            //将XML配置文件的信息解析成Java的Configuration对象
            //this.build根据Configuration对象创建出DefaultSqlSessionFactory对象
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

            try {
                inputStream.close();
            } catch (IOException var13) {
                ;
            }

        }
        return var5;
    }
  1. XMLConfigBuilder会将XML配置文件的信息转换为Document对象,而XML配置定义文件DTD转换成XMLMapperEntityResolver对象,然后将二者封装到XpathParser对象中,XpathParser的作用是提供根据Xpath表达式获取基本DOM节点Node信息的操作。
(1)/*XMLConfigBuilder*/
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
        this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
    }

/*XPathParser*/
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
        this.commonConstructor(validation, variables, entityResolver);
        this.document = this.createDocument(new InputSource(inputStream));
    }
  1. 之后XMLConfigBuilder调用parse方法,会从XPathParser中取出<configuration>节点对应的Node对象,然后解析Node节点的子节点:包括properties, settings, typeAliases,typeHandlers, objectFactory, objectWrapperFactory, plugins, environments,databaseIdProvider, mappers。
/*XMLConfigBuilder*/
 public Configuration parse() {
        if (this.parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        } else {
            this.parsed = true;
            this.parseConfiguration(this.parser.evalNode("/configuration"));
            return this.configuration;
        }
    }

/*
	解析"/configuration"节点下的子节点信息,然后将解析的结果设置到Configuration对象中
*/
    private void parseConfiguration(XNode root) {
        try {
            this.propertiesElement(root.evalNode("properties"));
            Properties settings = this.settingsAsProperties(root.evalNode("settings"));
            this.loadCustomVfs(settings);
            this.typeAliasesElement(root.evalNode("typeAliases"));
            this.pluginElement(root.evalNode("plugins"));
            this.objectFactoryElement(root.evalNode("objectFactory"));
            this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
            this.settingsElement(settings);
            this.environmentsElement(root.evalNode("environments"));
            this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            this.typeHandlerElement(root.evalNode("typeHandlers"));
            this.mapperElement(root.evalNode("mappers"));
        } catch (Exception var3) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
        }
    }
  1. 然后将这些值解析出来设置到Configuration对象中,以Environments为例:

Configuration类包含的属性:

public class Configuration {
    protected Environment environment;
    protected boolean safeRowBoundsEnabled;
    protected boolean safeResultHandlerEnabled;
    protected boolean mapUnderscoreToCamelCase;
    protected boolean aggressiveLazyLoading;
    protected boolean multipleResultSetsEnabled;
    protected boolean useGeneratedKeys;
    protected boolean useColumnLabel;
    protected boolean cacheEnabled;
    protected boolean callSettersOnNulls;
  ...
    protected final Collection<ResultMapResolver> incompleteResultMaps;
    protected final Collection<MethodResolver> incompleteMethods;
    protected final Map<String, String> cacheRefMap;
  • Environment
    在这里插入图片描述
    其中TransactionFactory由ManagedTransactionFactory实现对应xml标签中的transactionManager;
/*XMLConfigBuilder*/
 private void environmentsElement(XNode context) throws Exception {
        if (context != null) {
            if (this.environment == null) {
                this.environment = context.getStringAttribute("default");
            }

            Iterator var2 = context.getChildren().iterator();

            while(var2.hasNext()) {
                XNode child = (XNode)var2.next();
                String id = child.getStringAttribute("id");
                if (this.isSpecifiedEnvironment(id)) {
                //1. 创建事务工厂
                    TransactionFactory txFactory = this.transactionManagerElement(child.evalNode("transactionManager"));
                //2. 创建数据源    
                    DataSourceFactory dsFactory = this.dataSourceElement(child.evalNode("dataSource"));
                    DataSource dataSource = dsFactory.getDataSource();
                //3. 构造Environment对象    
                    Builder environmentBuilder = (new Builder(id)).transactionFactory(txFactory).dataSource(dataSource);
                //4. 将创建Environment对象设置到Configuration对象中。   
                    this.configuration.setEnvironment(environmentBuilder.build());
                }
            }
        }

    }

/*Environment*/
/*
	注意:创建environment时,如果SqlSessionFactoryBuilder制定了额特定环境;则返回指定数据眼的Environment对象,否则返回默认的Environment对象;这种方式实现了Mybatis可以连接多数据源。
*/
public Environment build() {
            return new Environment(this.id, this.transactionFactory, this.dataSource);
        }
       
  1. 返回Configuration对象
    在这里插入图片描述
    在这里插入图片描述

如何获取sql语句

  • 通过调用SqlSessionFactoryBuilder的build方法的,返回DefaultSqlSessionFactory对象;
  • 将解析好的configuration对象传入DefaultSqlSessionFactory构造器中,创建一个DefaultSqlSessionFactory对象。
  • 再通过调用DefaultSqlSessionFactory的openSession方法返回一个DefaultSqlSession对象。
  • SqlSession接口里面包含了jdbc里面的增删改查方法,其实就是底层封装了jdbc,通过jdbc来操作数据库。
/*SqlSessionFactoryBuilder*/
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
        	//建造xmlConfiguration对象(1)
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            //将XML配置文件的信息解析成Java的Configuration对象
            //this.build根据Configuration对象创建出DefaultSqlSessionFactory对象
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

            try {
                inputStream.close();
            } catch (IOException var13) {
                ;
            }

        }
        return var5;
    }

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

/*DefaultSqlSessionFactory*/
 public SqlSession openSession() {
 		//第一个参数为配置中的指定的执行器类型包含    SIMPLE,REUSE,BATCH;
 		//第二个参数为配置中事务的隔离级别:NONE(0),
		  // READ_COMMITTED(2),
		  // READ_UNCOMMITTED(1),
		  // REPEATABLE_READ(4),
		  // SERIALIZABLE(8);
		//第三个参数表示是否自动提交事务
        return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
    }

 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            //从environment对象中获取事务管理对象,如果没有则创建一个(1);
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            //创建一个事务实例
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            //根据执行器类型个事务对象创建一个执行器(2)
            Executor executor = this.configuration.newExecutor(tx, execType);
            //创建DefaultSqlSession对象,并返回
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

(1)获取事务工厂

//如果environment不为空并且environment配置中指定了事务工厂TransactionFactory则返回它,否则创建一个事务工厂管理对象。
 private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
        return (TransactionFactory)(environment != null && environment.getTransactionFactory() != null ? environment.getTransactionFactory() : new ManagedTransactionFactory());
    }

(2)创建执行器的方法

    public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    	//如果没有指定创建器类型,则默认使用SIMPLE类型
        executorType = executorType == null ? this.defaultExecutorType : executorType;
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
        Object executor;
        if (ExecutorType.BATCH == executorType) {
            executor = new BatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {
            executor = new ReuseExecutor(this, transaction);
        } else {
            executor = new SimpleExecutor(this, transaction);
        }
        if (this.cacheEnabled) {
            executor = new CachingExecutor((Executor)executor);
        }

        Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
        return executor;
    }

拿到sql如何去执行?

 @Test
    public void select(){
        SqlSession sqlSession = factory.openSession();
        Student stu = sqlSession.selectOne("mapper.StudentMapper.select", 1);
        sqlSession.close();
        System.out.println(stu);
    }

来看看Student stu = sqlSession.selectOne("mapper.StudentMapper.select", 1);都做了什么事。

  • 将获取到的MappedStatement对象传入query方法中。在BaseExecutor类中:
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        List var5;
        try {
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            (1)
            var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception var9) {
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
        } finally {
            ErrorContext.instance().reset();
        }

        return var5;
    }
  • select方法调用configuration的getMappedStatement方法传入sql语句statement返回这个语句节点对象;
    在这里插入图片描述
  • MappedStatement中包含BoundSql对象

MappedStatement维护了一条<select|update|delete|insert>节点的封装;获取的方式为命令空间+id;
SqlSource 负责根据用户传递的parameterObject动态的生成SQL语句,将信息封装到BoundSql对象中,并返回;
BoundSql表示动态生成的SQL语句以及相应的参数信息。有了BoundSql就可以执行sql语句了;

(1)

 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
 		//获取BoundSql对象
 		(2)
        BoundSql boundSql = ms.getBoundSql(parameter);
        //创建一级缓存,再调用该对象的重载方法query
        CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
        return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
/*MappedStatement*/
public BoundSql getBoundSql(Object parameterObject) {
        BoundSql boundSql = this.sqlSource.getBoundSql(parameterObject);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings == null || parameterMappings.isEmpty()) {
            boundSql = new BoundSql(this.configuration, boundSql.getSql(), this.parameterMap.getParameterMappings(), parameterObject);
        }

public class DynamicSqlSource implements SqlSource {
    private final Configuration configuration;
    private final SqlNode rootSqlNode;

/*DynamicSqlSource*/
    public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
        this.configuration = configuration;
        this.rootSqlNode = rootSqlNode;
    }
//根据配置和参数对象动态sql生成
    public BoundSql getBoundSql(Object parameterObject) {
        DynamicContext context = new DynamicContext(this.configuration, parameterObject);
        //读取sql结点对象(1),动态组建完整的sql语句
        this.rootSqlNode.apply(context);
        SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(this.configuration);
        Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
        //context.getSql()获取sql语句是完整的sql语句的原始形式包括#{}等
        //将sql语句解析为staticSqlSource(2)
        SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
        //用staticSqlSource构建boundSql
        BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
        Iterator var7 = context.getBindings().entrySet().iterator();
	//添加metaParameter
        while(var7.hasNext()) {
            Entry<String, Object> entry = (Entry)var7.next();
            boundSql.setAdditionalParameter((String)entry.getKey(), entry.getValue());
        }

        return boundSql;
    }
}
/*SqlSourceBuilder*/
public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
        SqlSourceBuilder.ParameterMappingTokenHandler handler = new SqlSourceBuilder.ParameterMappingTokenHandler(this.configuration, parameterType, additionalParameters);
        //解析#{}形式的参数
        GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
        //解析后的sql为用"?"替换#{}参数,且提取对应参数的ParameterMapping
        String sql = parser.parse(originalSql);
        //以StaticSqlSource为解析结果
        return new StaticSqlSource(this.configuration, sql, handler.getParameterMappings());
    }

动态sql结点对象,可以看到常用的<foreach>、<set>等标签;
在这里插入图片描述

 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    //如果连接关闭则抛出异常
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    //如果查询栈中记录为0或者刷新了缓存则清空缓存;
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
  ...
 		//先从缓存中获取,如果缓存中没有则冲数据库中获取
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) {
      //处理本地缓存的输出参数
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {
      //从数据库中查询
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
      queryStack--;
    }
private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) {
        if (ms.getStatementType() == StatementType.CALLABLE) {
            Object cachedParameter = this.localOutputParameterCache.getObject(key);
            if (cachedParameter != null && parameter != null) {
                MetaObject metaCachedParameter = this.configuration.newMetaObject(cachedParameter);
                MetaObject metaParameter = this.configuration.newMetaObject(parameter);
                Iterator var8 = boundSql.getParameterMappings().iterator();

                while(var8.hasNext()) {
                    ParameterMapping parameterMapping = (ParameterMapping)var8.next();
                    if (parameterMapping.getMode() != ParameterMode.IN) {
                        String parameterName = parameterMapping.getProperty();
                        Object cachedValue = metaCachedParameter.getValue(parameterName);
                        metaParameter.setValue(parameterName, cachedValue);
                    }
                }
            }
        }
    }
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

        List list;
        try {
        	//执行查询
            list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
        	//清空旧的缓存
            this.localCache.removeObject(key);
        }
			//创建新的缓存
        this.localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
            this.localOutputParameterCache.putObject(key, parameter);
        }
        //返回查询结果的List集合
        return list;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值