该系列文档是本人在学习 Mybatis 的源码过程当中总结下来的,可能对读者不太友好,请结合个人源码注释(Mybatis源码分析 GitHub 地址、Mybatis-Spring 源码分析 GitHub 地址、Spring-Boot-Starter 源码分析 GitHub 地址)进行阅读html
MyBatis 版本:3.5.2java
MyBatis-Spring 版本:2.0.3git
MyBatis-Spring-Boot-Starter 版本:2.1.4github
在前面一系列的文档中,已经详细的介绍了 MyBatis 的初始化和执行 SQL 的过程,在执行 SQL 的过程当中,还存在着一些疑问,例如其中一直提到的 SqlSession 会话在 MyBatis 中是如何被建立的?如何调用 Executor 执行器执行 SQL 的?spring
那么接下来就关于上面两个的两个问题,一块儿来探讨一下 MyBatis 中 SqlSession 会话的相关内容sql
先回顾一下《基础支持层》的Binding模块,每一个Mapper Interface
会有对应的MapperProxyFactory
动态代理对象工厂,用于建立MapperProxy
动态代理对象,Mapper 接口中的每一个方法都有对应的MapperMethod
对象,该对象会经过 SqlSession 会话执行数据操做数据库
再来看到这张MyBatis总体图:apache
在单独使用 MyBatis 进行数据库操做时,须要经过SqlSessionFactoryBuilder
构建一个SessionFactory
对象,而后经过它建立一个SqlSession
会话进行数据库操做数组
咱们一般都会先调用SqlSession
会话的getMapper(Class<T> mapper)
方法,为 Mapper 接口生成一个“实现类”(JDK动态代理对象),而后就能够经过它进行数据库操做缓存
// <1> 构建 SqlSessionFactory 对象 Reader reader = Resources.getResourceAsReader("org/apache/ibatis/autoconstructor/mybatis-config.xml"); // <2> 默认 DefaultSqlSessionFactory 对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); // <3> 得到 SqlSession 对象,默认 DefaultSqlSession 对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // <4> 得到 Mapper 对象 final AutoConstructorMapper mapper = sqlSession.getMapper(AutoConstructorMapper.class); // <5> 执行查询 final Object subject = mapper.getSubject(1);
org.apache.ibatis.session.SqlSessionFactoryBuilder
:构建SqlSessionFactory工厂类,里面定义了许多build重载方法,主要分为处理Reader和InputStream两种文件资源对象,代码以下:
public class SqlSessionFactoryBuilder { public SqlSessionFactory build(Reader reader) { return build(reader, null, null); } public SqlSessionFactory build(Reader reader, String environment) { return build(reader, environment, null); } public SqlSessionFactory build(Reader reader, Properties properties) { return build(reader, null, properties); } /** * 构造 SqlSessionFactory 对象 * * @param reader Reader 对象 * @param environment 环境 * @param properties Properties 变量 * @return SqlSessionFactory 对象 */ public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { /* * <1> 建立 XMLConfigBuilder 对象 * 会生成一个 XPathParser,包含 Document 对象 * 会建立一个 Configuration 全局配置对象 */ XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); /* * <2> 解析 XML 文件并配置到 Configuration 全局配置对象中 * <3> 建立 DefaultSqlSessionFactory 对象 */ return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null); } public SqlSessionFactory build(InputStream inputStream, String environment) { return build(inputStream, environment, null); } public SqlSessionFactory build(InputStream inputStream, Properties properties) { return build(inputStream, null, properties); } public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); 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. } } } public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); } }
在《MyBatis初始化(一)之加载mybatis-config.xml》中已经分析了,这里就再也不赘述,就是根据文件资源建立Configuration全局配置对象,而后构建一个DefaultSqlSessionFactory对象
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
:实现 SqlSessionFactory 接口,默认的 SqlSessionFactory 实现类
openSession
方法,建立一个DefaultSqlSession
对象,以下:
public class DefaultSqlSessionFactory implements SqlSessionFactory { private final Configuration configuration; public DefaultSqlSessionFactory(Configuration configuration) { this.configuration = configuration; } @Override public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } @Override public SqlSession openSession(boolean autoCommit) { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit); } @Override public SqlSession openSession(ExecutorType execType) { return openSessionFromDataSource(execType, null, false); } @Override public SqlSession openSession(TransactionIsolationLevel level) { return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false); } @Override public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) { return openSessionFromDataSource(execType, level, false); } @Override public SqlSession openSession(ExecutorType execType, boolean autoCommit) { return openSessionFromDataSource(execType, null, autoCommit); } @Override public SqlSession openSession(Connection connection) { return openSessionFromConnection(configuration.getDefaultExecutorType(), connection); } @Override public SqlSession openSession(ExecutorType execType, Connection connection) { return openSessionFromConnection(execType, connection); } }
openSession
有不少重载的方法,主要是提供如下几种入参的支持:
类型 | 参数名称 | 默认值 | 描述 |
---|---|---|---|
boolean | autoCommit | false | 事务是否自动提交 |
ExecutorType | execType | ExecutorType.SIMPLE | Executor执行器类型 |
TransactionIsolationLevel | level | 无 | 事务隔离级别 |
java.sql.Connection | connection | 无 | 数据库链接 |
内部直接调用openSessionFromDataSource
私有方法,内部也须要调用openSessionFromConnection
私有方法,若是存在connection
入参,内部则直接调用openSessionFromConnection
私有方法
openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)
方法,用于建立一个DefaultSqlSession
对象,方法以下:
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 对象 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(); } }
Environment
当前环境对象getTransactionFactoryFromEnvironment
方法,从 Environment 环境对象中TransactionFactory
对象,用于建立一个Transaction
事务Executor
执行器对象DefaultSqlSession
对象openSessionFromConnection(ExecutorType execType, Connection connection)
方法,用于建立一个DefaultSqlSession
对象
和上面的方法逻辑相同,只不过它的入参直接传入了一个Connection数据库链接,方法以下:
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) { try { // 得到是否能够自动提交 boolean autoCommit; try { autoCommit = connection.getAutoCommit(); } catch (SQLException e) { // Failover to true, as most poor drivers // or databases won't support transactions autoCommit = true; } // 得到 Environment 对象 final Environment environment = configuration.getEnvironment(); // 建立 Transaction 对象 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); final Transaction tx = transactionFactory.newTransaction(connection); // 建立 Executor 对象 final Executor executor = configuration.newExecutor(tx, execType); // 建立 DefaultSqlSession 对象 return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
和上面的方法不一样的是,建立Transaction
事务对象时,传入的参数直接是Connection
数据库链接对象
getTransactionFactoryFromEnvironment(Environment environment)
方法,用于建立一个TransactionFactory
对象,在建立 SqlSessionFactory 时,就能够经过设置 Environment 的 DataSource 数据源和 TransactionFactory 事务工厂来集成第三方数据源和事务管理器,代码以下:
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) { // 状况一,建立 ManagedTransactionFactory 对象 if (environment == null || environment.getTransactionFactory() == null) { return new ManagedTransactionFactory(); } // 状况二,使用 `environment` 中的 return environment.getTransactionFactory(); }
closeTransaction(Transaction tx)
方法,关闭事务,方法以下:
private void closeTransaction(Transaction tx) { if (tx != null) { try { tx.close(); } catch (SQLException ignore) { // Intentionally ignore. Prefer previous error. } } }
org.apache.ibatis.session.defaults.DefaultSqlSession
:实现 SqlSession 接口,默认的 SqlSession 实现类,调用 Executor 执行器,执行数据库操做
public class DefaultSqlSession implements SqlSession { /** * 全局配置 */ private final Configuration configuration; /** * 执行器对象 */ private final Executor executor; /** * 是否自动提交事务 */ private final boolean autoCommit; /** * 是否发生数据变动 */ private boolean dirty; /** * Cursor 数组 */ private List<Cursor<?>> cursorList; public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) { this.configuration = configuration; this.executor = executor; this.dirty = false; this.autoCommit = autoCommit; } }
执行数据库查询操做,提供了许多重载方法
@Override public void select(String statement, Object parameter, ResultHandler handler) { select(statement, parameter, RowBounds.DEFAULT, handler); } @Override public void select(String statement, ResultHandler handler) { select(statement, null, RowBounds.DEFAULT, handler); } @Override public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { try { MappedStatement ms = configuration.getMappedStatement(statement); executor.query(ms, wrapCollection(parameter), rowBounds, handler); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } @Override public <T> T selectOne(String statement) { return this.selectOne(statement, null); } @Override public <T> T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. List<T> list = this.selectList(statement, parameter); if (list.size() == 1) { return list.get(0); } else if (list.size() > 1) { throw new TooManyResultsException( "Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); } else { return null; } } @Override public <K, V> Map<K, V> selectMap(String statement, String mapKey) { return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT); } @Override public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) { return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT); } @Override public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { // <1> 执行查询 final List<? extends V> list = selectList(statement, parameter, rowBounds); // <2> 建立 DefaultMapResultHandler 对象 final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey, configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory()); // <3> 建立 DefaultResultContext 对象 final DefaultResultContext<V> context = new DefaultResultContext<>(); // <4> 遍历查询结果 for (V o : list) { // 设置 DefaultResultContext 中 context.nextResultObject(o); // 使用 DefaultMapResultHandler 处理结果的当前元素 mapResultHandler.handleResult(context); } // <5> 返回结果 return mapResultHandler.getMappedResults(); } @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> 得到 MappedStatement 对象 MappedStatement ms = configuration.getMappedStatement(statement); // <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(); } }
上面有不少的数据库查询方法,主要分为如下几种:
select
:执行数据库查询操做,经过入参中的ResultHandler
处理结果集,无返回结果selectList
:执行数据库查询操做,返回List集合selectOne
:调用selectList
方法,执行数据库查询操做,最多只能返回一条数据selectMap
:调用selectList
方法,执行数据库查询操做,经过DefaultMapResultHandler
进行处理,将返回结果转换成Map集合能够看到经过Executor执行器的query
方法执行查询操做,能够回顾《SQL执行过程(一)之Executor》中的内容
这里会先调用wrapCollection
方法对入参进行包装(若是是集合类型)
执行数据库更新操做
@Override public int insert(String statement) { return insert(statement, null); } @Override public int insert(String statement, Object parameter) { return update(statement, parameter); } @Override public int delete(String statement) { return update(statement, null); } @Override public int delete(String statement, Object parameter) { return update(statement, parameter); } @Override public int update(String statement) { return update(statement, null); } @Override public int update(String statement, Object parameter) { try { // <1> 标记 dirty ,表示执行过写操做 dirty = true; // <2> 得到 MappedStatement 对象 MappedStatement ms = configuration.getMappedStatement(statement); // <3> 执行更新操做 return executor.update(ms, wrapCollection(parameter)); } catch (Exception e) { throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
insert
和delete
方法最终都是调用update
方法,经过Executor执行器的update
方法执行数据库更新操做
这里会先调用wrapCollection
方法对入参进行包装(若是是集合类型)
wrapCollection(final Object object)
方法,将集合类型的参数包装成StrictMap
对象,方法以下:
public static class StrictMap<V> extends HashMap<String, V> { private static final long serialVersionUID = -5741767162221585340L; @Override public V get(Object key) { if (!super.containsKey(key)) { throw new BindingException( "Parameter '" + key + "' not found. Available parameters are " + this.keySet()); } return super.get(key); } } 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; }
getMapper(Class<T> type)
方法,获取Mapper接口的代理对象
@Override public <T> T getMapper(Class<T> type) { return configuration.getMapper(type, this); }
经过Configuration
全局配置对象获取一个动态代理对象
实际经过MapperRegistry
注册表获取到该Mapper接口对应的MapperProxyFactory
动态代理工厂,而后建立一个MapperProxy
动态代理的实例对象
flushStatements()
:提交批处理commit()
:提交事务rollback()
:回滚事务close()
:关闭当前会话getConnection()
:获取当前事务的数据库链接clearCache()
:清理一级缓存org.apache.ibatis.binding.MapperMethod
:Mapper接口中定义的方法对应的Mapper方法,经过它来执行SQL
先来看看执行一个SQL的完整流程图:
在《基础支持层》的Binding模块已经讲过了相关的内容,例如看到前面示例的第4
步,经过DefaultSqlSession
的getMapper
方法会执行如下操做:
MapperProxyFactory
动态代理对象工厂newInstance
方法会建立一个MapperProxy
接口代理类,而后返回该Mapper接口的动态代理对象当你调用这个接口的某个方法时,会进入这个MapperProxy
代理类,咱们来看到它的invoke
方法是如何实现的,方法以下:
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // <1> 若是是 Object 定义的方法,直接调用 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else if (method.isDefault()) { // 是否有 default 修饰的方法 // 针对Java7以上版本对动态类型语言的支持 if (privateLookupInMethod == null) { return invokeDefaultMethodJava8(proxy, method, args); } else { return invokeDefaultMethodJava9(proxy, method, args); } } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } // <2.1> 得到 MapperMethod 对象 final MapperMethod mapperMethod = cachedMapperMethod(method); // <2.2> 执行 MapperMethod 方法 return mapperMethod.execute(sqlSession, args); }
首先获取到方法对应的MapperMethod
对象,而后经过该对象去执行数据库的操做
public Object execute(SqlSession sqlSession, Object[] args) { // 根据 SqlCommand 的 Type 判断应该如何执行 SQL 语句 Object result; switch (command.getType()) { case INSERT: { // <1> 获取参数值与参数名的映射 Object param = method.convertArgsToSqlCommandParam(args); // <2> 而后经过 SqlSession 进行数据库更新操做,并将受影响行数转换为结果 result = rowCountResult(sqlSession.insert(command.getName(), param)); break; } case UPDATE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); break; } case DELETE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); break; } case SELECT: if (method.returnsVoid() && method.hasResultHandler()) { // 无返回,且入参中有 ResultHandler 结果处理器 executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) { // 执行查询,返回列表 result = executeForMany(sqlSession, args); } else if (method.returnsMap()) { // 执行查询,返回 Map result = executeForMap(sqlSession, args); } else if (method.returnsCursor()) { // 执行查询,返回 Cursor 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; }
根据 SqlCommand 的 Type 判断应该如何执行 SQL 语句,类型分为INSERT
、UPDATE
、DELETE
、SELECT
和FLUSH
(进行批处理)五种
前三种都属于数据库的更新操做,调用的是DefaultSqlSession
的update
方法,经过rowCountResult(int rowCount)
将受影响行数转换为返回对象
查询语句的话就分为如下几种状况:
ResultHandler
结果处理器,则调用executeWithResultHandler
方法,执行查询,返回结果设置为nullexecuteForMany
方法,执行查询,返回列表executeForMap
方法,执行查询,返回MapexecuteForCursor
方法,执行查询,返回CursorDefaultSqlSession
的selectOne
方法,执行查询,返回单个对象上面执行数据库操做前会先调用convertArgsToSqlCommandParam
方法,获取参数值与参数名的映射
convertArgsToSqlCommandParam(Object[] args)
方法,根据入参返回参数名称与入参的映射,方法以下:
public Object convertArgsToSqlCommandParam(Object[] args) { return paramNameResolver.getNamedParams(args); }
在《基础支持层》的反射模块的ParamNameResolver小节已经分析过该方法,能够跳过去看看
rowCountResult(int rowCount)
方法,将受影响行数转换为结果,方法以下:
private Object rowCountResult(int rowCount) { final Object result; if (method.returnsVoid()) { result = null; } else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) { result = rowCount; } else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) { result = (long) rowCount; } else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) { result = rowCount > 0; } else { throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType()); } return result; }
executeWithResultHandler(SqlSession sqlSession, Object[] args)
方法,经过入参中定义的ResultHandler结果处理器执行查询,方法以下:
private void executeWithResultHandler(SqlSession sqlSession, Object[] args) { // <1> 得到 MappedStatement 对象 MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName()); /* * <2> 配置校验 * 由于入参定义了 ResultHandler 结果处理器,因此若是不是存储过程,且没有配置返回结果的 Java Type,则会抛出异常 */ if (!StatementType.CALLABLE.equals(ms.getStatementType()) && void.class.equals(ms.getResultMaps().get(0).getType())) { throw new BindingException( "method " + command.getName() + " needs either a @ResultMap annotation, a @ResultType annotation," + " or a resultType attribute in XML so a ResultHandler can be used as a parameter."); } // <3> 获取参数名称与入参的映射 Object param = method.convertArgsToSqlCommandParam(args); // <4> 执行数据库查询操做 if (method.hasRowBounds()) { // <4.1> 入参定义了 RowBounds 分页对象 // <4.1.1> 获取入参定义了 RowBounds 分页对象 RowBounds rowBounds = method.extractRowBounds(args); // <4.1.2> 执行查询 sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args)); } else { // <4.2> 执行查询 sqlSession.select(command.getName(), param, method.extractResultHandler(args)); } }
MappedStatement
对象ResultHandler
结果处理器,因此若是不是存储过程,且没有配置返回结果的 Java Type,则会抛出异常RowBounds
分页对象,则获取该对象,而后执行查询,传入分析对象executeForMany(SqlSession sqlSession, Object[] args)
方法,执行查询,返回列表,方法以下:
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) { List<E> result; // 获取参数名称与入参的映射 Object param = method.convertArgsToSqlCommandParam(args); // 执行数据库查询操做 if (method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); // 执行查询,返回 List 集合 result = sqlSession.selectList(command.getName(), param, rowBounds); } else { // 执行查询,返回 List 集合 result = sqlSession.selectList(command.getName(), param); } // issue #510 Collections & arrays support // 封装 Array 或 Collection 结果 if (!method.getReturnType().isAssignableFrom(result.getClass())) { // 若是不是 List 集合类型 if (method.getReturnType().isArray()) { // 将 List 转换成 Array 数组类型的结果 return convertToArray(result); } else { // 转换成其余 Collection 集合类型的结果 return convertToDeclaredCollection(sqlSession.getConfiguration(), result); } } // 直接返回 List 集合类型的结果 return result; }
executeForMap(SqlSession sqlSession, Object[] args)
方法,执行查询,返回Map,方法以下:
private <K, V> Map<K, V> executeForMap(SqlSession sqlSession, Object[] args) { Map<K, V> result; // 获取参数名称与入参的映射 Object param = method.convertArgsToSqlCommandParam(args); // 执行 SELECT 操做 if (method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); // 执行查询,返回 Map 集合 result = sqlSession.selectMap(command.getName(), param, method.getMapKey(), rowBounds); } else { // 执行查询,返回 Map 集合 result = sqlSession.selectMap(command.getName(), param, method.getMapKey()); } return result; }
本分分析了 SqlSession 会话在 MyBatis 中是如何被建立,如何获取到 Mapper 接口的动态代理对象,经过该动态代理对象是如何执行 SQL 的
SqlSessionFactoryBuilder
构造器提供build
方法,根据mybatis-config.xml
配置文件对 MyBatis 进行初始化,生成Configuration
对象,用于构建一个DefaultSqlSessionFactory
对象
经过1
生成的 SqlSession 工厂对象,咱们能够构建一个DefaultSqlSession
会话对象,经过这个会话对象的getMapper(Class<T> mapper)
方法,能够为 Mapper 接口建立一个动态代理对象
(JDK动态代理),其动态代理类为MapperProxy
对象
调用 Mapper 接口的某个方法时,会进入相应的MapperProxy
代理类,根据方法对应的MapperMethod
对象,执行数据库操做
执行数据库相关操做,调用的就是上面的DefaultSqlSession
会话对象的相关方法,该会话内部则会经过Executor
执行器去执行数据库的相关操做,并返回执行结果
好了,对于 MyBatis 总体上全部的内容已经所有分析完了,相信你们对 MyBatis 有了一个全面认识,其中确定有不对或者迷惑的地方,欢迎指正!!!感谢你们的阅读!!!😄😄😄
参考文章:芋道源码《精尽 MyBatis 源码分析》