在上一篇博客中提到MyBatis是如何实现代理类MapperProxy,并抛出了一个问题——是怎么执行一个具体的sql语句的,在文末中提到了MapperMethod的execute采用命令模式来判断是何种sql语句,并将具体语句的执行交由SqlSession处理。所以此篇博客正是要讲到SqlSession。

  在SqlSession接口中包含了所有可能执行的sql语句在这里不一一列举,请参考org.apache.ibatis.session.SqlSession源码。DefaultSqlSession是SqlSession的实现类,所以我们重点关注DefaultSqlSession类。在上一篇博客中提到了我们将选择MapperProxy的executeForMany方法。在此方法中调用了SqlSession.<E>selectList方法。所以我们来看看org.apache.ibatis.session.default.DefaultSqlSession类的selectList方法。

 //org.apache.ibatis.session.defaults.DefaultSqlSession
……
@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 {
MappedStatement ms = configuration.getMappedStatement(statement);
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();
}
}
……

我们看到关于selectList有三个重载方法,最后调用的都是public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds)。在此方法中第一个参数为String类型且命名为statement,第二个参数为Object命名为parameter,回到MapperMethod。

 //org.apache.ibatis.binding.MapperMethod
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.<E>selectList(command.getName(), param, rowBounds);  //注意传递了什么参数进来
} else {
result = sqlSession.<E>selectList(command.getName(), param);
}
// issue #510 Collections & arrays support
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}

  第7行代码可以看到传递了什么参数进来,跟踪command.getName()是怎么来的。

private final SqlCommand command;

  看来是一个叫做SqlCommand的变量,进而我们可以发现这个SqlCommand是MapperMethod的静态内部类。

 //org.apache.ibatis.binding.MapperMethod
public static class SqlCommand { private final String name;
private final SqlCommandType type; public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
String statementName = mapperInterface.getName() + "." + method.getName();  //获取接口+方法名
MappedStatement ms = null;  //定义一个MappedStatement,这个MapperedStatement稍后介绍
if (configuration.hasStatement(statementName)) {  //从Configuration对象查找是否有这个方法的全限定名称
ms = configuration.getMappedStatement(statementName);  //有,则根据方法的全限定名称获取MappedStatement实例
} else if (!mapperInterface.equals(method.getDeclaringClass())) { // issue #35//如果没有在Configuration对象中找到这个方法,则向上父类中获取全限定方法名
String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName();
if (configuration.hasStatement(parentStatementName)) {  //在向上的父类查找是否有这个全限定方法名
ms = configuration.getMappedStatement(parentStatementName);   //有,则根据方法的全限定名称获取MappedStatement实例
}
}
if (ms == null) {
if(method.getAnnotation(Flush.class) != null){
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException("Invalid bound statement (not found): " + statementName);
}
} else {
name = ms.getId();  //这个ms.getId,其实就是我们在mapper.xml配置文件中配置一条sql语句时开头的<select id="……"……,即是接口的该方法名全限定名称
type = ms.getSqlCommandType();  //显然这是将sql是何种类型(insert、update、delete、select)赋给type
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
} public String getName() {
return name;
} public SqlCommandType getType() {
return type;
}
}

  大致对MapperMethod的解读到此,再次回到DefaultSqlSession中,到这里可能稍微有点混乱。画个图来理解这一段,希望能帮助理解。

  这次又一次回到了DefaultSqlSession.selectList。此处不再贴出selectList所有方法,而是只贴出一句,根据接口方法的全限定名称获取MappedStatement。

MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

  在获取到MappedStatement后,碰到了第一个SqlSession下的四大对象之一:Executor执行器。看来还是没有讲到SqlSession,再放到下一节吧。可以思考下这个MappedStatement是什么意思,望文生义就能猜出个大概。

这是一个能给程序员加buff的公众号

MyBatis源码解读(4)——SqlSession(上)的更多相关文章

  1. MyBatis源码解读(3)——MapperMethod

    在前面两篇的MyBatis源码解读中,我们一路跟踪到了MapperProxy,知道了尽管是使用了动态代理技术使得我们能直接使用接口方法.为巩固加深动态代理,我们不妨再来回忆一遍何为动态代理. 我相信在 ...

  2. spring IOC DI AOP MVC 事务, mybatis 源码解读

    demo https://gitee.com/easybao/aop.git spring DI运行时序 AbstractApplicationContext类的 refresh()方法 1: pre ...

  3. Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?

    Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的?   如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...

  4. Mybatis源码解读-SpringBoot中配置加载和Mapper的生成

    本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...

  5. Mybatis源码解读-插件

    插件允许对Mybatis的四大对象(Executor.ParameterHandler.ResultSetHandler.StatementHandler)进行拦截 问题 Mybatis插件的注册顺序 ...

  6. MyBatis源码解读之延迟加载

    1. 目的 本文主要解读MyBatis 延迟加载实现原理 2. 延迟加载如何使用 Setting 参数配置 设置参数 描述 有效值 默认值 lazyLoadingEnabled 延迟加载的全局开关.当 ...

  7. MyBatis源码解读(1)——SqlSessionFactory

    在前面对MyBatis稍微有点了解过后,现在来对MyBatis的源码试着解读一下,并不是解析,暂时定为解读.所有对MyBatis解读均是基于MyBatis-3.4.1,官网中文文档:http://ww ...

  8. 【转】Mybatis源码解读-设计模式总结

    原文:http://www.crazyant.net/2022.html?jqbmtw=b90da1&gsjulo=kpzaa1 虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开 ...

  9. Mybatis源码分析之SqlSession和Excutor(二)

    通过上一篇文章的分析我们,我初步了解了它是如何创建sessionFactory的(地址:Mybatis源码分析之SqlSessionFactory(一)), 今天我们分析下Mybatis如何创建Sql ...

  10. Mybatis源码解读-设计模式总结

    虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开发中很少遇到,Mybatis源码中使用了大量的设计模式,阅读源码并观察设计模式在其中的应用,能够更深入的理解设计模式. Mybatis至少 ...

随机推荐

  1. h5 做app时和原生交互的小常识。

    距离上次随笔或许有半年了吧,最近在用hybrid模式开发移动app,所以就简单的说说用h5技术开发app时候,做原生交互的几个小常识: 一.拨打电话或者发送短信: <a href="t ...

  2. JAVA-实例方法被覆盖,静态方法被隐藏Explain

    被覆盖比较好理解,类似于多态的实现. 被隐藏是指静态方法的访问是根据当前对象的表面类型来决定的,比如 Supers = new Sub(); s.greeting()访问的是Super的静态方法,如果 ...

  3. CF #405 (Div. 2) B. Bear ad Friendship Condition (dfs+完全图)

    题意:如果1认识2,2认识3,必须要求有:1认识3.如果满足上述条件,输出YES,否则输出NO. 思路:显然如果是一个完全图就输出YES,否则就输出NO,如果是无向完全图则一定有我们可以用dfs来书边 ...

  4. Mybatis基础学习(二)—开发Dao方式

    一.原始Dao开发方式 UserDao.java public interface UserDao{ public User findUserByID(Serializable id); public ...

  5. BZOJ1857 传送带 (三分法求单峰函数极值)

    第一次发BZOJ的题解,先从水题开始吧,好不容易找到一道水题,那就从这题开始吧. 1.题设部分{ 题目描述: 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段.两条传送带分别为线段AB和线 ...

  6. 24(java_io from keyboard)

    public class ReadFromKB{ public static void main(String args[]) { try { byte bArray[]=new byte[128]; ...

  7. iOS各框架功能简述以及系统层次结构简单分析

    iOS各个框架所对应的功能简单介绍 iOS系统结构层次:

  8. Spring Boot 整合 Redis 实现缓存操作

    摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢!   『 产品没有价值,开发团队再优秀也无济于事 – <启示录> 』   本文提纲 ...

  9. Apache设置404页面

    使用版本:Apache 2.2 1.添加404页面 在所配置网站的根目录添加编辑好的 404.html (页面名字无所谓 比如也可以叫missing.html) 如C:\Program Files\A ...

  10. 【shell编程基础2】shell组合应用之一:重定向和逻辑

    这篇主要讲下 数据的重定向,在shell脚本中有些重要的输出重定向为文件的形式输出来 逻辑方式的多个命令组合,可以很方便的进行一些判断 数据流重定向 数据流重定向:大致上的意思就是本该输出到屏幕上的数 ...