MyBatis源码阅读--执行流程

MyBatis源码阅读-总索引

MyBatis源码阅读–执行流程

前言

MyBatis有两种方式执行SQL,第一种是调用SqlSession的相关方法去执行,第二种是通过SqlSession获取Mapper接口,通过动态代理,其最终也是调用SqlSession的相关方法去执行,但是第二种方法比较常用而且更加方便。本问主要讲解使用第二种方式执行的流程。
在这里插入图片描述

执行流程

获取SqlSession

通过SqlSessionFactoryBuilder获取SqlSessionFactory

  //1.获取配置文件的输入流
  Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
  //2.通过SqlSessionFactoryBuilder获取SqlSessionFactory
  SqlSessionFactory    sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

查看build()方法

 public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
        //通过输入流构建XMLConfigBuilder对象
            XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
            //parser.parse()返回的是Configuration类型对象
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

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

        }

        return var5;
    }

查看parser.parse()方法

 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;
        }
    }
     //解析配置文件节点
     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);
        }
    }

利用Configuration对象创建DefaultSqlSessionFactory对象

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

从上面可以看出:获取SqlSessionFactory的流程是:
1.使用Resources类将配置文件转换成输入流
2.通过SqlSessionFactoryBuilder.build(Reader reader, String environment, Properties properties)构建
3.通过输入流创建XMLConfigBuilder对象,并使用XMLConfigBuilder.parse()方法将输入流转换为Configuration对象
4.利用Configuration对象创建DefaultSqlSessionFactory对象

通过SqlSessionFactory获取SqlSession

SqlSession sqlSession = SqlSessionFactory.openSession();

openSession 最终调用的是openSessionFromDataSource方法。
有两种方式,第一种是从dataSource,第二种是从Connection连接来创建。

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

        DefaultSqlSession var8;
        try {
           //获取Environment对象,包括environment id,DataSource , 事物工厂
            Environment environment = this.configuration.getEnvironment();
            //通过事务工厂获取事务
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            //创建执行器Executor
            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;
    }
 private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
        DefaultSqlSession var8;
        try {
            boolean autoCommit;
            try {
                autoCommit = connection.getAutoCommit();
            } catch (SQLException var13) {
                autoCommit = true;
            }

            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            Transaction tx = transactionFactory.newTransaction(connection);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var14, var14);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }
    

从上面可以看,通过SqlSessionFactory获取SqlSession的流程是:
1.通过configuration对象获取Environment对象,包括environment id,DataSource , 事物工厂
2.通过事务工厂获取事务
3.创建执行器Executor
4.创建DefaultSqlSession对象。

获取Mapper

调用SqlSession的getMapper方法获取,其调用的Configuration类的getMapper()方法
这里的type为需要获取的mapper接口。

public <T> T getMapper(Class<T> type) {
   return this.configuration.getMapper(type, this);
}

来看Configuration类的getMapper()方法,其调用的是mapperRegistry类的getMapper方法,参数是接口和当前的sqlSession。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
   return this.mapperRegistry.getMapper(type, sqlSession);
}
    

MapperRegistry类的getMapper方法,这里先获取一个MapperProxyFactory对象,并通过MapperProxyFactory的newInstance来创建Mapper对象。
knownMappers是一个MapperProxyFactory的HashMap对象。
相关的MapperProxyFactory对象是在解析配置文件并初始化时创建并添加进去的。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {

        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }

继续查看MapperProxyFactory类的newInstance方法

public T newInstance(SqlSession sqlSession) {
  MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
   return this.newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
   return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}

到这里为止,就创建了mapper接口的动态代理对象,而被代理的方法被放到MapperProxy类中。因此获取Mapper对象就是一个创建其动态代理的过程。

通过Mapper执行sql

上一节说明了如何创建mapper接口的动态代理对象,接下来讲解使用该动态代理对象执行Sql 的流程。
创建好mapper对象后,使用很简单,直接只用该对象调用接口内的相关方法即可。

sysUserMapper = sqlSession1.getMapper(SysUserMapper.class);
 sysUser1 = sysUserMapper.selectByPrimaryKey(1030L);

看一下执行时的调用栈
在这里插入图片描述
1.调用方法selectByPrimaryKey
2.调用MapperProxy类的invoke方法
3.调用MapperMethod类的execute方法,并返回结果
4.调用DefaultSqlSession(SqlSession的子类)的selectOne,最终调用的是selectList方法
5.selectList方法中通过执行器executor去执行Sql语句,并返回结果,由于使用了缓存,因此这里的执行器是CachingExecutor。

MapperProxy类的invoke方法

org.apache.ibatis.binding.MapperProxy

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            }
            if (this.isDefaultMethod(method)) {
                return this.invokeDefaultMethod(proxy, method, args);
            }
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }
        MapperMethod mapperMethod = this.cachedMapperMethod(method);
        return mapperMethod.execute(this.sqlSession, args);
    }

上一节提到mapper被代理的方法被放到MapperProxy类中,因此调用mapper方法后,将会调用MapperProxy类的invoke方法。
这是传入invoke方法的参数
在这里插入图片描述

之后调用MapperMethod类的execute方法

  MapperMethod mapperMethod = this.cachedMapperMethod(method);
        return mapperMethod.execute(this.sqlSession, args);

MapperMethod类的execute方法

org.apache.ibatis.binding.MapperMethod

 public Object execute(SqlSession sqlSession, Object[] args) {
        Object param;
        Object result;
        switch(this.command.getType()) {
        case INSERT:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
            break;
        case UPDATE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
            break;
        case DELETE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
            break;
        case SELECT:
            if (this.method.returnsVoid() && this.method.hasResultHandler()) {
                this.executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (this.method.returnsMany()) {
                result = this.executeForMany(sqlSession, args);
            } else if (this.method.returnsMap()) {
                result = this.executeForMap(sqlSession, args);
            } else if (this.method.returnsCursor()) {
                result = this.executeForCursor(sqlSession, args);
            } else {
                param = this.method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(this.command.getName(), param);
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            throw new BindingException("Unknown execution method for: " + this.command.getName());
        }

        if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
            throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
        } else {
            return result;
        }
    }

这里采用命令模式,根据mapper配置文件和传入的接口名称和方法,获取当前执行的sql是什么操作。可以看到,不管是什么操作,其最终都是调用SqlSession中的相关方法。
所以使用SqlSession方式或者通过mapper方式去执行,最终都是执行SqlSession中的方法,只是使用mapper方式更加简单。

SqlSession使用执行其executor执行sql并返回结果

不管是update或者insert等操作,都是使用执行器去执行.
Executor接口:

public interface Executor {
    ResultHandler NO_RESULT_HANDLER = null;
    int update(MappedStatement var1, Object var2) throws SQLException;
    <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException;
    <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;
        <E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException;
    List<BatchResult> flushStatements() throws SQLException;
    void commit(boolean var1) throws SQLException;
    void rollback(boolean var1) throws SQLException;
    CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4);
    boolean isCached(MappedStatement var1, CacheKey var2);
    void clearLocalCache();
    void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class<?> var5);
    Transaction getTransaction();
    void close(boolean var1);
    boolean isClosed();
    void setExecutorWrapper(Executor var1);
}

DefaultSqlSession类:

//select最终调用
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        List var5;
        try {
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            //使用执行器
            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;
    }
    
    //delete,update ,insert 最终调用
    public int update(String statement, Object parameter) {
        int var4;
        try {
            this.dirty = true;
            MappedStatement ms = this.configuration.getMappedStatement(statement);
              //使用执行器
            var4 = this.executor.update(ms, this.wrapCollection(parameter));
        } catch (Exception var8) {
            throw ExceptionFactory.wrapException("Error updating database.  Cause: " + var8, var8);
        } finally {
            ErrorContext.instance().reset();
        }

        return var4;
    }
    

到此,整个执行流程讲解完。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页