每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML (mybatis-config.xml) 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

类图

其中SqlSession是比较重要的接口,提供基本的方法,比如:sql语句、事务等操作;

具体执行过程以<E> List<E> selectList(String statement);方法为例:SqlSession的实现类DefaultSqlSession调用configuration.getMappedStatement(statement);获取statement节点的sql,存放在MappedStatement,传给接口Executor的query方法。

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

Executor处理MappedStatement的关键代码和注释如下

   // 是否需要刷新缓存
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
// 如果缓存中有数据,直接拿到缓存中的数据
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 否则从数据库中获取
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
   private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
// 把查询结果放入缓存后返回结果list
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
   @Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
// 用来执行静态sql语句的对象
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
// StatementHandler中处理sql的执行和结果的返回
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
   @Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
return resultSetHandler.<E>handleResultSets(statement);
}

参考文档

MyBatis官方文档

MyBatis源码探索的更多相关文章

  1. mybatis源码探索笔记-5(拦截器)

    前言 mybatis中拦截器主要用来拦截我们在发起数据库请求中的关键步骤.其原理也是基于代理模式,自定义拦截器时要实现Interceptor接口,并且要对实现类进行标注,声明是对哪种组件的指定方法进行 ...

  2. mybatis源码探索笔记-1(构建SqlSessionFactory)

    前言 mybatis是目前进行java开发 dao层较为流行的框架,其较为轻量级的特性,避免了类似hibernate的重量级封装.同时将sql的查询与与实现分离,实现了sql的解耦.学习成本较hibe ...

  3. mybatis源码探索笔记-4(缓存原理)

    前言 mybatis的缓存大家都知道分为一级和二级缓存,一级缓存系统默认使用,二级缓存默认开启,但具体用的时候需要我们自己手动配置.我们依旧还是先看一个demo.这儿只贴出关键代码 public in ...

  4. mybatis源码探索笔记-3(使用代理mapper执行方法)

    前言 前面两章我们构建了SqlSessionFactory,并通过SqlSessionFactory创建了我们需要的SqlSession,并通过这个SqlSession获取了我们需要的代理mapper ...

  5. mybatis源码探索笔记-2(构建SqlSession并获取代理mapper)

    前言 上篇笔记我们成功的装载了Configuration,并写入了我们全部需要的信息.根据这个Configuration创建了DefaultSqlSessionFactory.本篇我们实现构建SqlS ...

  6. MyBatis 源码分析 - 缓存原理

    1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 Redis 或 memcached 等缓存中间件,拦截大量奔向数据库的请求,减轻数据库压力.作为一个重要的组件,MyBatis 自然 ...

  7. MyBatis 源码分析 - 内置数据源

    1.简介 本篇文章将向大家介绍 MyBatis 内置数据源的实现逻辑.搞懂这些数据源的实现,可使大家对数据源有更深入的认识.同时在配置这些数据源时,也会更清楚每种属性的意义和用途.因此,如果大家想知其 ...

  8. MyBatis 源码分析 - SQL 的执行过程

    * 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析 ...

  9. Mybatis源码解析优秀博文

    最近阅读了许久的mybatis源码,小有所悟.同时也发现网上有许多优秀的mybatis源码讲解博文.本人打算把自己阅读过的.觉得不错的一些博文列出来.以此进一步加深对mybatis框架的理解.其实还有 ...

随机推荐

  1. p2590&bzoj1036 树的统计

    传送门(洛谷) 传送门(bzoj) 题目 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值 ...

  2. Struts简单入门实例

    转自http://www.cnblogs.com/xing901022/p/3961661.html 有改动 struts2其实就是为我们封装了servlet,简化了jsp跳转的复杂操作,并且提供了易 ...

  3. 使用IDEA编译netty4

    本来计划一天一篇博文的,结果周末加班加的不亦乐乎,对整个项目重构添加国际化的功能,不停的使用native2ascii工具 使用IDEA编译原有的netty4要报错,我修改了下pom.xml,编译成功了 ...

  4. 经典DP 嵌套矩形 (南洋理工ACM—16)

    本来是个很水的DP,结果被自己的代码习惯给打败了 代码: #include<iostream> #include<stdlib.h> #include<string.h& ...

  5. 【Sping管理bean的原理】

    spring容器默认情况下,当服务启动时,解析配置文件,实例化文件中的所有类. 我们直接使用spring时,获取spring注入的bean是这样的, ApplicationContext ctx =  ...

  6. 虚拟创建失败之Dbus调试

    DBus调试命令 查询连接名 ### 查询所有连接名 # dbus-send --system --print-reply --dest=org.freedesktop.DBus / org.free ...

  7. HQuorumPeer和QuorumPeerMain进程的区别

    HBase是列式数据库,既可以单机也可以集群的方式搭建,以集群的方式搭建一般建立在HDFS之上. 分布式HBase启动说明:首先启动hadoop,然后问题就来了:zookeeper和hbase的启动顺 ...

  8. HDU2048 神、上帝以及老天爷

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2048 看书发现了这道题,刚开始没理解题意,以为是中奖的概率,---> 1/n 后来知道了是典型的错排 ...

  9. thinkphp5.1常量定义使用

    thinkphp5.1取消了系统常量 可以把常量配置在app.php文件中 //配置网站地址 'WEB_URL'=>'http://127.0.0.1/tp5', 可以使用config()函数直 ...

  10. ROS上利用usb_cam读取摄像头图像

    电脑需要有USB3.0的接口 我使用的环境为:Ubuntu16.04LTS ROS版本是kinetic 一.usb_cam驱动的安装 1.创建ROS工作空间 mkdir -p myros/src cd ...