Mybatis-架构原理

Mybatis架构原理
架构设计

Mybatis架构设计图

我们把Mybatis的功能分为三层:

  1. API接口层:提供给开发人员调用API接口;接口一接收到请求,会调用数据处理层完成数据交互。Mybatis提供了两种API方式工开发人员调用:
    • 传统调用SqlSession接口方式,使用StatementId确定唯一SQL
    • 使用Mapper代理方式,动态代理接口实现
  2. 数据处理层:负责具体的数据库交互,解析参数,解析SQL,执行SQL,组装结果集;
  3. 基础支持层:负责最基础的功能支持,包括连接管理,事务管理,配置加载,缓存梳理等;
主要构件及其关系
构件功能
SqlSession作为直接跟开发人员交互的API调用层,表示和数据库的会话,完成必要的数据库增删改查功能
ExecutorMybatis的执行器,负责SQL语句生成和缓存维护
StatementHandler封装JDBC Statement操作
ParameterHandler负责对用户传递参数装换成JDBC Statement需要参数
ResultSetHandler负责将JDBC返回ResultSet,转化为List集合
TypeHandler负责java类型和SQL类型映射转换
MappedStatement负责存储开发人员自定义SQL数据<select|update|delete|insert>
SqlSource负责将ParameterObject动态生成SQL语句,将信息封装到BoundSQL中
BoundSQL动态生成SQL语句及相关参数信息

Mybatis各组件层次结构

Mybatis的执行流程
  1. 加载配置文件并初始化
    • 触发条件:程序启动加载配置文件
    • 说明:配置文件来源于两个地方,一个是配置文件(SQLMapConfig.xml,XXXMapper.xml),一个是java代码中注解配置;
    • 处理过程:将SQLMapConfig.xml封装到Configuration中,将XXXMapper.xml等SQL信息封装到MappedStatement对象中;
  2. 接收调用请求
    • 触发条件:调用Mybatis提供的API
    • 传入参数:SQL的ID(statementID),传入的参数对象
    • 处理过程:调用数据处理层进行数据库操作
  3. 处理操作请求:
    • 触发条件:API接口层传递请求过来
    • 传入参数:SQL的ID(statementID),传入的参数对象
    • 处理过程:
      a. 根据SQLID获取对应SQL信息MappedStatement
      b. 根据传入参数,解析MappedStatement获取最终JDBC执行需要的SQL和参数
      c. 获取数据库连接,执行SQL,获取执行结果
      d. 解析MappedStatement获取返回结果对象描述,处理执行结果,获取最终返回结果;
      e. 释放资源
  4. 返回处理结果
Mybatis源码分析
传统方式分析
整体调用流程
// 1. 读取配置文件,读成字节输入流,注意:现在还没解析
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

// 2. 解析配置文件,封装Configuration对象   创建DefaultSqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

// 3. 生产了DefaultSqlsession实例对象   设置了事务不自动提交  完成了executor对象的创建
SqlSession sqlSession = sqlSessionFactory.openSession();

// 4.(1)根据statementid来从Configuration中map集合中获取到了指定的MappedStatement对象
    // (2)将查询任务委派了executor执行器
List<Object> objects = sqlSession.selectList("namespace.id");

// 5.释放资源
sqlSession.close();
解析配置文件创建SqlSessionFactory

SqlSessionFactoryBuilder

// 1.我们最初调用的build
public SqlSessionFactory build(InputStream inputStream) {
    //调用了重载方法
    return build(inputStream, null, null);
}
// 2.调用的重载方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
        // 创建 XMLConfigBuilder, XMLConfigBuilder是专门解析mybatis的配置文件的类
        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
        // 执行 XML 解析
        // 创建 DefaultSqlSessionFactory 对象 2.1 2.2
        return build(parser.parse());
    } 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.
        }
    }
}
// 2.2 创建 DefaultSqlSessionFactory 对象
public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config); //构建者设计模式
}

XMLConfigBuilder

// 2.1 解析 XML 成 Configuration 对象。
public Configuration parse() {
    // 若已解析,抛出 BuilderException 异常
    if (parsed) {
        throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    // 标记已解析
    parsed = true;
    ///parser是XPathParser解析器对象,读取节点内数据,<configuration>是MyBatis配置文件中的顶层标签
    // 解析 XML configuration 节点
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
}
// 2.1.1 解析 XML configuration 节点 具体配置解析
private void parseConfiguration(XNode root) {
    try {
        //issue #117 read properties first
        // 解析 <properties /> 标签
        propertiesElement(root.evalNode("properties"));
        // 解析 <settings /> 标签
        Properties settings = settingsAsProperties(root.evalNode("settings"));
        // 加载自定义的 VFS 实现类
        loadCustomVfs(settings);
        // 解析 <typeAliases /> 标签
        typeAliasesElement(root.evalNode("typeAliases"));
        // 解析 <plugins /> 标签
        pluginElement(root.evalNode("plugins"));
        // 解析 <objectFactory /> 标签
        objectFactoryElement(root.evalNode("objectFactory"));
        // 解析 <objectWrapperFactory /> 标签
        objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
        // 解析 <reflectorFactory /> 标签
        reflectorFactoryElement(root.evalNode("reflectorFactory"));
        // 赋值 <settings /> 到 Configuration 属性
        settingsElement(settings);
        // read it after objectFactory and objectWrapperFactory issue #631
        // 解析 <environments /> 标签
        environmentsElement(root.evalNode("environments"));
        // 解析 <databaseIdProvider /> 标签
        databaseIdProviderElement(root.evalNode("databaseIdProvider"));
        // 解析 <typeHandlers /> 标签
        typeHandlerElement(root.evalNode("typeHandlers"));
        // 解析 <mappers /> 标签
        mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
}
生产了DefaultSqlsession实例对象

DefaultSqlSessionFactory

//1. 进入openSession方法
@Override
public SqlSession openSession() {
    //getDefaultExecutorType()传递的是SimpleExecutor
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
//2. 进入openSessionFromDataSource。
//ExecutorType 为Executor的类型,TransactionIsolationLevel为事务隔离级别,autoCommit是否开启事务
//openSession的多个重载方法可以指定获得的SeqSession的Executor类型和事务的处理
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
        // 获得 Environment 对象
        final Environment environment = configuration.getEnvironment();
        // 创建 Transaction 对象
        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        // 创建 Executor 对象 2.1
        final Executor executor = configuration.newExecutor(tx, execType);
        // 创建 DefaultSqlSession 对象
        return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
        // 如果发生异常,则关闭 Transaction 对象
        closeTransaction(tx); // may have fetched a connection so lets call close()
        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

Configuration 配置类

// 2.1 创建Executor
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    // 获得执行器类型
    executorType = executorType == null ? defaultExecutorType : executorType; // 使用默认
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType; // 使用 ExecutorType.SIMPLE
    // 创建对应实现的 Executor 对象
    Executor 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);
    }
    // 如果开启缓存,创建 CachingExecutor 对象,进行包装
    if (cacheEnabled) {
        // 缓存执行器包装
        executor = new CachingExecutor(executor);
    }
    // 应用插件
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}
根据statementID,执行SQL

DefaultSqlSession 默认会话对象

//1.进入selectList方法,多个重载方法
@Override
public <E> List<E> selectList(String statement) {
    return this.selectList(statement, null);
}
@Override
public <E> List<E> selectList(String statement, Object parameter) {
    // 添加默认分页配置
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
        //1.1 获得 MappedStatement 对象
        MappedStatement ms = configuration.getMappedStatement(statement);
        //1.2 执行查询
        return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}
// 1.2.1 处理集合参数
private Object wrapCollection(final Object object) {
    if (object instanceof Collection) {
        // 如果是集合,则添加到 collection 中
        StrictMap<Object> map = new StrictMap<>();
        map.put("collection", object);
        // 如果是 List ,则添加到 list 中
        if (object instanceof List) {
            map.put("list", object);
        }
        return map;
    } else if (object != null && object.getClass().isArray()) {
        // 如果是 Array ,则添加到 array 中
        StrictMap<Object> map = new StrictMap<>();
        map.put("array", object);
        return map;
    }
    return object;
}

BaseExecutor 执行器基类

// 1.2.2 此方法在SimpleExecutor的父类BaseExecutor中实现
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    //根据传入的参数动态获得SQL语句,最后返回用BoundSql对象表示
    BoundSql boundSql = ms.getBoundSql(parameter);
    //为本次查询创建缓存的Key
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    // 查询 1.2.2.1
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
// 1.2.2.1
@Override
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());
    // 已经关闭,则抛出 ExecutorException 异常
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
    // 清空本地缓存,如果 queryStack 为零,并且要求清空本地缓存。
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
        clearLocalCache();
    }
    List<E> list;
    try {
        // queryStack + 1
        queryStack++;
        // 从一级缓存中,获取查询结果
        list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
        // 获取到,则进行处理
        if (list != null) {
            // 存储过程返回结果处理
            handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
        // 获得不到,则从数据库中查询
        } else {
            // 1.2.2.1.1
            list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
        }
    } finally {
        // queryStack - 1
        queryStack--;
    }
    if (queryStack == 0) {
        // 执行延迟加载
        for (DeferredLoad deferredLoad : deferredLoads) {
            deferredLoad.load();
        }
        // issue #601
        // 清空 deferredLoads
        deferredLoads.clear();
        // 如果缓存级别是 LocalCacheScope.STATEMENT ,则进行清理
        if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
            // issue #482
            clearLocalCache();
        }
    }
    return list;
}
// 1.2.2.1.1从数据库中读取操作
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    // 在缓存中,添加占位对象。此处的占位符,和延迟加载有关,可见 `DeferredLoad#canLoad()` 方法
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
        // 2.1 执行读操作
        list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
        // 从缓存中,移除占位对象
        localCache.removeObject(key);
    }
    // 添加到缓存中
    localCache.putObject(key, list);
    // 暂时忽略,存储过程相关
    if (ms.getStatementType() == StatementType.CALLABLE) {
        localOutputParameterCache.putObject(key, parameter);
    }
    return list;
}

SimpleExecutor 简单执行器类

// 2.1 执行查询操作
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
        Configuration configuration = ms.getConfiguration();
        // 传入参数创建StatementHanlder对象来执行查询
        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
        // 创建jdbc中的statement对象
        stmt = prepareStatement(handler, ms.getStatementLog());
        // 2.2 执行 StatementHandler  ,进行读操作
        return handler.query(stmt, resultHandler);
    } finally {
        // 关闭 StatementHandler 对象
        closeStatement(stmt);
    }
}

PreparedStatementHandler 预编译处理器类

// 2.2 执行查询
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    // 执行查询
    ps.execute();
    // 3.1 处理返回结果
    return resultSetHandler.handleResultSets(ps);
}

DefaultResultSetHandler 处理结果集类

// 3.1 处理 {@link java.sql.ResultSet} 结果集
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    // 多 ResultSet 的结果集合,每个 ResultSet 对应一个 Object 对象。而实际上,每个 Object 是 List<Object> 对象。
    // 在不考虑存储过程的多 ResultSet 的情况,普通的查询,实际就一个 ResultSet ,也就是说,multipleResults 最多就一个元素。
    final List<Object> multipleResults = new ArrayList<>();

    int resultSetCount = 0;
    // 获得首个 ResultSet 对象,并封装成 ResultSetWrapper 对象
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    // 获得 ResultMap 数组
    // 在不考虑存储过程的多 ResultSet 的情况,普通的查询,实际就一个 ResultSet ,也就是说,resultMaps 就一个元素。
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount); // 校验
    while (rsw != null && resultMapCount > resultSetCount) {
        // 获得 ResultMap 对象
        ResultMap resultMap = resultMaps.get(resultSetCount);
        // 处理 ResultSet ,将结果添加到 multipleResults 中
        handleResultSet(rsw, resultMap, multipleResults, null);
        // 获得下一个 ResultSet 对象,并封装成 ResultSetWrapper 对象
        rsw = getNextResultSet(stmt);
        // 清理
        cleanUpAfterHandlingResultSet();
        // resultSetCount ++
        resultSetCount++;
    }

    // 因为 `mappedStatement.resultSets` 只在存储过程中使用,本系列暂时不考虑,忽略即可
    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
        while (rsw != null && resultSetCount < resultSets.length) {
            ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
            if (parentMapping != null) {
                String nestedResultMapId = parentMapping.getNestedResultMapId();
                ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
                handleResultSet(rsw, resultMap, null, parentMapping);
            }
            rsw = getNextResultSet(stmt);
            cleanUpAfterHandlingResultSet();
            resultSetCount++;
        }
    }

    // 如果是 multipleResults 单元素,则取首元素返回
    return collapseSingleResultList(multipleResults);
}
Mapper代理方式分析
整体执行流程
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = factory.openSession();

// 使用JDK动态代理对mapper接口产生代理对象
IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);

//代理对象调用接口中的任意方法,执行的都是动态代理中的invoke方法
List<Object> allUser = mapper.findAllUser();

解析配置文件,获取SqlSession流程和传统方式一样,这里只说一下注册Mapper和获取Mapper的方式

注册Mapper

在解析XML配置文件中,会有一步解析Mappers配置文件的,最终会调用configuration.addMapper(mapperInterface);将解析完成的mapper添加到Configuration中,之后就可以从configuration中获取

// 添加解析完成的mapper文件 到mapperRegistry
public <T> void addMapper(Class<T> type) {
    mapperRegistry.addMapper(type);
}
// 获取代理mapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}
获取Mapper

DefaultSqlSession

// 1. 获取Mapper
@Override
public <T> T getMapper(Class<T> type) {
    return configuration.getMapper(type, this);
}

Configuration

// 2. 获取Mapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}
```java
MapperRegistry
```java
// 3. 获取Mapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 获得 MapperProxyFactory 对象
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    // 不存在,则抛出 BindingException 异常
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    //3.1 通过动态代理工厂生成实例。
    try {
        return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
        throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}

MapperProxyFactory

//3.1 MapperProxyFactory类中的newInstance方法
public T newInstance(SqlSession sqlSession) {
    // 创建了JDK动态代理的invocationHandler接口的实现类mapperProxy
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    // 调用了重载方法
    return newInstance(mapperProxy);
}
// 3.2 创建代理对象
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
}
代理mapper执行

代理对象执行全部通过MapperProxy中的invoke方法
MapperProxy

// 1. 执行代理方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        // 如果是 Object 定义的方法,直接调用
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);

        } else if (isDefaultMethod(method)) {
            return invokeDefaultMethod(proxy, method, args);
        }
    } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
    }
    // 获得 MapperMethod 对象
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    // 2.1 重点在这:MapperMethod最终调用了执行的方法
    return mapperMethod.execute(sqlSession, args);
}
MapperMethod
```java
// 2.1 最终代理对象执行的方法
public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //判断mapper中的方法类型,最终调用的还是SqlSession中的方法
    switch (command.getType()) {
        case INSERT: {
            // 转换参数
            Object param = method.convertArgsToSqlCommandParam(args);
            // 执行 INSERT 操作
            // 转换 rowCount
            result = rowCountResult(sqlSession.insert(command.getName(), param));
            break;
        }
        case UPDATE: {
            // 转换参数
            Object param = method.convertArgsToSqlCommandParam(args);
            // 转换 rowCount
            result = rowCountResult(sqlSession.update(command.getName(), param));
            break;
        }
        case DELETE: {
            // 转换参数
            Object param = method.convertArgsToSqlCommandParam(args);
            // 转换 rowCount
            result = rowCountResult(sqlSession.delete(command.getName(), param));
            break;
        }
        case SELECT:
            // 无返回,并且有 ResultHandler 方法参数,则将查询的结果,提交给 ResultHandler 进行处理
            if (method.returnsVoid() && method.hasResultHandler()) {
                executeWithResultHandler(sqlSession, args);
                result = null;
            // 执行查询,返回列表
            } else if (method.returnsMany()) {
                result = executeForMany(sqlSession, args);
            // 执行查询,返回 Map
            } else if (method.returnsMap()) {
                result = executeForMap(sqlSession, args);
            // 执行查询,返回 Cursor
            } else if (method.returnsCursor()) {
                result = executeForCursor(sqlSession, args);
            // 执行查询,返回单个对象
            } else {
                // 转换参数
                Object param = method.convertArgsToSqlCommandParam(args);
                // 查询单条
                result = sqlSession.selectOne(command.getName(), param);
                if (method.returnsOptional() &&
                        (result == null || !method.getReturnType().equals(result.getClass()))) {
                    result = Optional.ofNullable(result);
                }
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            throw new BindingException("Unknown execution method for: " + command.getName());
    }
    // 返回结果为 null ,并且返回类型为基本类型,则抛出 BindingException 异常
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
        throw new BindingException("Mapper method '" + command.getName()
                + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    // 返回结果
    return result;
}

可以看出,Mapper代理最终执行的还是传统的SqlSession方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值