每个基于 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方法。

  1. @Override
  2. public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  3. try {
  4. MappedStatement ms = configuration.getMappedStatement(statement);
  5. return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  6. } catch (Exception e) {
  7. throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
  8. } finally {
  9. ErrorContext.instance().reset();
  10. }
  11. }

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

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

参考文档

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. 面试题17:打印1到最大的n位数

    // 面试题17:打印1到最大的n位数 // 题目:输入数字n,按顺序打印出从1最大的n位十进制数.比如输入3,则 // 打印出1.2.3一直到最大的3位数即999. 解题思路: 首先是一个大陷阱,n ...

  2. 会过vip怎么赚钱?大学生,宝妈创业圈子

    会过vip怎么赚钱?是骗局吗1.如果说会过Vip不赚钱,那么一定是我们的没有时间去真心的热爱她:如果你对她如果你对它抱着一颗平和的心,认真的去分享,认真的去听一些前辈的经验,赚钱真的不是难事:2.如果 ...

  3. 使用js页面添加或删除标签

    // 添加var container = document.getElementById('divAudio');container.appendChild(audio); // 删除var cont ...

  4. android 手写万能adapter适配器

    android开发中,我们离不开adapter,每个项目都有很多地方需要adapter,那么我们如何让自己少写adapter代码呢?那就是封装adapter,让我们的adapter成为万能的adapt ...

  5. 前后分离调用API跨域

    前后分离调用API接口跨域问题 什么是跨域?  跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的. 广义的跨域: 资源跳转:A链接.重定向.表单提交. 资源嵌入: <li ...

  6. ios 检测是否安装微信异常

    解决方法 在info.plist 添加LSApplicationQueriesSchemes 类型是Array weixin wechat

  7. MySQL服务器与MySQL57服务器区别与不同处在哪里,他们各自的领域范围,能不能同时启动服务?

    安装了MySQL-5.7.18.0版本数据库,版本中包含了MySQL Workbench可视化试图工具,在服务列表栏中会有MySQL的两个服务器:如果启动第一项MySQL服务器就只能操作数据库,外界不 ...

  8. 离散数学——python实现真值表和打印主范式

    最近用python实现了真值表,经过有点儿曲折,刚开始没考虑优先级,直到前天才发现这个问题(离散数学没学好啊),用栈改了一下.话说python就是强,把列表类型当栈用,直接调用列表的pop()和app ...

  9. SaltStack自动化安装配置haproxy的Keepalived

    keepalived配置安装 什么是vrrp,阿里云不支持组播,所以阿里云上不能配置keepalived,但是它有自己的slb.运维的大忌,在命令行复制粘贴,一般是先复制到文本中查看确认以后salt编 ...

  10. POJ3696 The Luckiest Number 欧拉定理

    昨天终于把欧拉定理的证明看明白了...于是兴冲冲地写了2道题,发现自己啥都不会qwq 题意:给定一个正整数L<=2E+9,求至少多少个8连在一起组成正整数是L的倍数. 这很有意思么... 首先, ...