博客
关于我
精尽MyBatis源码分析 - SqlSession 会话与 SQL 执行入口
阅读量:430 次
发布时间:2019-03-06

本文共 24883 字,大约阅读时间需要 82 分钟。

该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(、、)进行阅读

MyBatis 版本:3.5.2

MyBatis-Spring 版本:2.0.3

MyBatis-Spring-Boot-Starter 版本:2.1.4

该系列其他文档请查看:

SqlSession会话与SQL执行入口

在前面一系列的文档中,已经详细的介绍了 MyBatis 的初始化和执行 SQL 的过程,在执行 SQL 的过程中,还存在着一些疑问,例如其中一直提到的 SqlSession 会话在 MyBatis 中是如何被创建的?如何调用 Executor 执行器执行 SQL 的?

那么接下来就关于上面两个的两个问题,一起来探讨一下 MyBatis 中 SqlSession 会话的相关内容

先回顾一下的Binding模块,每个Mapper Interface会有对应的MapperProxyFactory动态代理对象工厂,用于创建MapperProxy动态代理对象,Mapper 接口中的每个方法都有对应的MapperMethod对象,该对象会通过 SqlSession 会话执行数据操作

再来看到这张MyBatis整体图:

在单独使用 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);

SqlSessionFactoryBuilder

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);	}}

在中已经分析了,这里就不再赘述,就是根据文件资源创建Configuration全局配置对象,然后构建一个DefaultSqlSessionFactory对象

DefaultSqlSessionFactory

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory:实现 SqlSessionFactory 接口,默认的 SqlSessionFactory 实现类

openSession方法

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方法

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();    }}
  1. 获得Environment当前环境对象
  2. 通过getTransactionFactoryFromEnvironment方法,从 Environment 环境对象中TransactionFactory对象,用于创建一个Transaction事务
  3. 然后再创建一个Executor执行器对象
  4. 根据全局配置对象、执行器和事务是否自动提交创建一个DefaultSqlSession对象

openSessionFromConnection方法

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方法

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方法

closeTransaction(Transaction tx)方法,关闭事务,方法如下:

private void closeTransaction(Transaction tx) {    if (tx != null) {        try {            tx.close();        } catch (SQLException ignore) {            // Intentionally ignore. Prefer previous error.        }    }}

DefaultSqlSession

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
> cursorList; public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) { this.configuration = configuration; this.executor = executor; this.dirty = false; this.autoCommit = autoCommit; }}

select方法

执行数据库查询操作,提供了许多重载方法

@Overridepublic void select(String statement, Object parameter, ResultHandler handler) {    select(statement, parameter, RowBounds.DEFAULT, handler);}@Overridepublic void select(String statement, ResultHandler handler) {    select(statement, null, RowBounds.DEFAULT, handler);}@Overridepublic 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();    }}@Overridepublic 
T selectOne(String statement) { return this.selectOne(statement, null);}@Overridepublic
T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. List
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; }}@Overridepublic
Map
selectMap(String statement, String mapKey) { return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);}@Overridepublic
Map
selectMap(String statement, Object parameter, String mapKey) { return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);}@Overridepublic
Map
selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { // <1> 执行查询 final List
list = selectList(statement, parameter, rowBounds); // <2> 创建 DefaultMapResultHandler 对象 final DefaultMapResultHandler
mapResultHandler = new DefaultMapResultHandler<>(mapKey, configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory()); // <3> 创建 DefaultResultContext 对象 final DefaultResultContext
context = new DefaultResultContext<>(); // <4> 遍历查询结果 for (V o : list) { // 设置 DefaultResultContext 中 context.nextResultObject(o); // 使用 DefaultMapResultHandler 处理结果的当前元素 mapResultHandler.handleResult(context); } // <5> 返回结果 return mapResultHandler.getMappedResults();}@Overridepublic
List
selectList(String statement) { return this.selectList(statement, null);}@Overridepublic
List
selectList(String statement, Object parameter) { return this.selectList(statement, parameter, RowBounds.DEFAULT);}@Overridepublic
List
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方法执行查询操作,可以回顾中的内容

这里会先调用wrapCollection方法对入参进行包装(如果是集合类型)

update方法

执行数据库更新操作

@Overridepublic int insert(String statement) {    return insert(statement, null);}@Overridepublic int insert(String statement, Object parameter) {    return update(statement, parameter);}@Overridepublic int delete(String statement) {    return update(statement, null);}@Overridepublic int delete(String statement, Object parameter) {    return update(statement, parameter);}@Overridepublic int update(String statement) {    return update(statement, null);}@Overridepublic 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();    }}

insertdelete方法最终都是调用update方法,通过Executor执行器的update方法执行数据库更新操作

这里会先调用wrapCollection方法对入参进行包装(如果是集合类型)

wrapCollection方法

wrapCollection(final Object object)方法,将集合类型的参数包装成StrictMap对象,方法如下:

public static class StrictMap
extends HashMap
{ 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
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 map = new StrictMap<>(); map.put("array", object); return map; } return object;}

getMapper方法

getMapper(Class<T> type)方法,获取Mapper接口的代理对象

@Overridepublic 
T getMapper(Class
type) { return configuration.getMapper(type, this);}

通过Configuration全局配置对象获取一个动态代理对象

实际通过MapperRegistry注册表获取到该Mapper接口对应的MapperProxyFactory动态代理工厂,然后创建一个MapperProxy动态代理的实例对象

其他方法

  • flushStatements():提交批处理
  • commit():提交事务
  • rollback():回滚事务
  • close():关闭当前会话
  • getConnection():获取当前事务的数据库连接
  • clearCache():清理一级缓存

MapperMethod

org.apache.ibatis.binding.MapperMethod:Mapper接口中定义的方法对应的Mapper方法,通过它来执行SQL

先来看看执行一个SQL的完整流程图:

在的Binding模块已经讲过了相关的内容,例如看到前面示例的第4步,通过DefaultSqlSessiongetMapper方法会执行以下操作:

  1. 创建Mapper接口对应的MapperProxyFactory动态代理对象工厂
  2. 通过这个工厂的newInstance方法会创建一个MapperProxy接口代理类,然后返回该Mapper接口的动态代理对象

当你调用这个接口的某个方法时,会进入这个MapperProxy代理类,我们来看到它的invoke方法是如何实现的,方法如下:

@Overridepublic 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对象,然后通过该对象去执行数据库的操作

execute方法

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 语句,类型分为INSERTUPDATEDELETESELECTFLUSH(进行批处理)五种

前三种都属于数据库的更新操作,调用的是DefaultSqlSessionupdate方法,通过rowCountResult(int rowCount)将受影响行数转换为返回对象

查询语句的话就分为以下几种情况:

  1. 无返回,且入参中有 ResultHandler 结果处理器,则调用executeWithResultHandler方法,执行查询,返回结果设置为null
  2. 返回对象为多条数据,则调用executeForMany方法,执行查询,返回列表
  3. 返回对象为Map类型,则调用executeForMap方法,执行查询,返回Map
  4. 返回对象为Cursor类型,则调用executeForCursor方法,执行查询,返回Cursor
  5. 返回对象为单个对象,则调用DefaultSqlSessionselectOne方法,执行查询,返回单个对象

上面执行数据库操作前会先调用convertArgsToSqlCommandParam方法,获取参数值与参数名的映射

convertArgsToSqlCommandParam方法

convertArgsToSqlCommandParam(Object[] args)方法,根据入参返回参数名称与入参的映射,方法如下:

public Object convertArgsToSqlCommandParam(Object[] args) {    return paramNameResolver.getNamedParams(args);}

在的反射模块ParamNameResolver小节已经分析过该方法,可以跳过去看看

rowCountResult方法

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方法

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));    }}
  1. 获得 MappedStatement 对象
  2. 配置校验,因为入参定义了 ResultHandler 结果处理器,所以如果不是存储过程,且没有配置返回结果的 Java Type,则会抛出异常
  3. 获取参数名称与入参的映射
  4. 执行数据库查询操作
    1. 入参定义了 RowBounds 分页对象,则获取该对象,然后执行查询,传入分析对象
    2. 没有定义则执行执行查询

executeForMany方法

executeForMany(SqlSession sqlSession, Object[] args)方法,执行查询,返回列表,方法如下:

private 
Object executeForMany(SqlSession sqlSession, Object[] args) { List
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;}
  1. 获取参数名称与入参的映射
  2. 执行数据库查询操作,获取到 List 集合结果
  3. 根据返回结果的类型进行转换
    1. 如果是 Array 数组类型,则将 List 转换成 Array 数组类型的结果
    2. 如果是其他集合类型,则将 List 转换成其他 Collection 集合类型的结果
    3. 否则直接返回 List 集合类型的结果

executeForMap方法

executeForMap(SqlSession sqlSession, Object[] args)方法,执行查询,返回Map,方法如下:

private 
Map
executeForMap(SqlSession sqlSession, Object[] args) { Map
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;}
  1. 获取参数名称与入参的映射
  2. 执行查询,返回 Map 集合

总结

本分分析了 SqlSession 会话在 MyBatis 中是如何被创建,如何获取到 Mapper 接口的动态代理对象,通过该动态代理对象是如何执行 SQL 的

  1. SqlSessionFactoryBuilder构造器提供build方法,根据mybatis-config.xml配置文件对 MyBatis 进行初始化,生成Configuration对象,用于构建一个DefaultSqlSessionFactory对象

  2. 通过1生成的 SqlSession 工厂对象,我们可以构建一个DefaultSqlSession会话对象,通过这个会话对象的getMapper(Class<T> mapper)方法,可以为 Mapper 接口创建一个动态代理对象(JDK动态代理),其动态代理类为MapperProxy对象

  3. 调用 Mapper 接口的某个方法时,会进入相应的MapperProxy代理类,根据方法对应的MapperMethod对象,执行数据库操作

  4. 执行数据库相关操作,调用的就是上面的DefaultSqlSession会话对象的相关方法,该会话内部则会通过Executor执行器去执行数据库的相关操作,并返回执行结果

好了,对于 MyBatis 整体上所有的内容已经全部分析完了,相信大家对 MyBatis 有了一个全面认识,其中肯定有不对或者迷惑的地方,欢迎指正!!!感谢大家的阅读!!!😄😄😄

参考文章:芋道源码

转载地址:http://szsyz.baihongyu.com/

你可能感兴趣的文章
Vue基础入门学习
查看>>
Spring Validation 校验
查看>>
如何使用Postman生成不同格式测试的报告
查看>>
Jmeter-ForEach控制器
查看>>
Jmeter发送jdbc请求(操作mysql)
查看>>
windows环境下安装zookeeper(仅本地使用)
查看>>
Pytest学习(二十)- allure之@allure.step()、allure.attach的详细使用
查看>>
Docker学习(十三)- docker rm 命令详解
查看>>
移动端Web开发调试之Chrome远程调试(Remote Debugging)
查看>>
解决Eclipse左键无法查看maven第三方包的源代码,多图亲测可用【转】
查看>>
selnium远程机上传图片遇到的坑
查看>>
idea如何编译maven项目
查看>>
Kali安装Docker
查看>>
ServerSuperIO Designer IDE 发布,打造物联网通讯大脑,随心而联。附:C#驱动源代码。
查看>>
Java 持久化操作之 --XML
查看>>
程序员如何提高工作效率
查看>>
(转)在ASP.NET 中实现单点登录(利用Cache, 将用户信息保存在服务器缓存中)
查看>>
【Azure 应用服务】在Azure Funciton中使用Powershell脚本函数,需要存储一些变量值如何解决?
查看>>
RabbitMQ核心概念篇
查看>>
权限管理系统系列之序言
查看>>