2019独角兽企业重金招聘Python工程师标准>>>

MyBatis 源码分析

  • MyBatis的主要成员

    • Configuration

      • MyBatis所有的配置信息都保存在Configuration对象之中,
      • 配置文件中的大部分配置都会存储到该类中
    • SqlSession            
      • 作为MyBatis工作的主要顶层API
      • 表示和数据库交互时的会话,完成必要数据库增删改查功能
    • Executor              
      • MyBatis执行器,
      • 是MyBatis 调度的核心,
      • 负责SQL语句的生成和查询缓存的维护
    • StatementHandler
      • 封装了JDBC Statement操作,
      • 负责对JDBC statement 的操作,
        • 如设置参数等
    • ParameterHandler  
      • 负责对用户传递的参数转换成JDBC Statement 所对应的数据类型
    • ResultSetHandler  
      • 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
    • TypeHandler          
      • 负责java数据类型和jdbc数据类型(也可以说是数据表列类型)之间的映射转换
    • MappedStatement  
      • MappedStatement维护一条<select|update|delete|insert>节点的封装
    • SqlSource              
      • 负责根据用户传递的parameterObject,
      • 动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
    • BoundSql              
      • 表示动态生成的SQL语句以及相应的参数信息
    • knownMappers.put(type, new MapperProxyFactory<T>(type));
    • sqlSessionFactory.openSession();
      • openSessionFromDataSource
  • spring-mybatis
    • ClassPathMapperScanner doScan方法的真正调用地方
      • definition.setBeanClass(this.mapperFactoryBean.getClass()); 注册 beanDefinition class 为mapperFactoryBean
    • xmlConfigBuilder
      • configuration = xmlConfigBuilder.getConfiguration();
    • XMLStatementBuilder
      • builderAssistant.addMappedStatement...
        • MappedStatement.Builder statementBuilder = new MappedStatement.Builder(...
    • XMLMapperBuilder  解析xml 配置文件,包括 mapper.xml 的配置
      • xmlMapperBuilder.parse();
        • bindMapperForNamespace 绑定 mapper
          • configuration.addMapper(boundType);
            • mapperRegistry.addMapper(type);
              • knownMappers.put(type, new MapperProxyFactory<T>(type));
    • return this.sqlSessionFactoryBuilder.build(configuration);
      • return new DefaultSqlSessionFactory(config);
    • MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
      • public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {if (!this.externalSqlSession) {this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);}
        }
    • SqlSessionTemplate 本质是 SqlSession 的装饰器
      • this.sqlSessionProxy = (SqlSession) newProxyInstance(   // sqlSessionProxy  本质是 SqlSession的动态代理new Class[] { SqlSession.class },new SqlSessionInterceptor());
    • if (!isEmpty(this.plugins)) {for (Interceptor plugin : this.plugins) { configuration.addInterceptor(plugin);   // 初始化插件if (LOGGER.isDebugEnabled()) {LOGGER.debug("Registered plugin: '" + plugin + "'");}}
      }
      • interceptorChain.addInterceptor(interceptor);
      • protected final InterceptorChain interceptorChain = new InterceptorChain();  // InterceptorChain 是configuration 的成员变量
      • 插件的调用是在 创建四大 Handler 的时候 执行 pluginAll
        • 是在程序执行阶段

          比如:doUpdate 时候,执行 newParameterHandler
          • StatementHandler handler = configuration.newStatementHandler(
            • public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);return parameterHandler;
              }
    • processPropertyPlaceHolders

      • 执行属性的处理,简单的说,

        • 就是把xml中${XXX}中的XXX替换成属性文件中的相应的值
    • findCandidateComponents
      • if (isCandidateComponent(sbd)) {
        • protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
          }
  • 初始化阶段:
    • spring源码学习之整合Mybatis原理分析
  • 程序运行阶段:
    • 基本运行:

      • public static void main(String[] args) {//定义 SqlSessionFactorySqlSessionFactory sqlSessionFactory = null;try {//使用配置文件创建 SqlSessionFactorysqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));} catch (IOException ex) {//打印异常.Logger.getLogger(MainCh1.class.getName()).fatal("创建 SqlSessionFactory失败", ex);return;}//定义 sqlSessionSqlSession sqlSession = null;try {//用sqlSessionFactory创建sqlSessionsqlSession = sqlSessionFactory.openSession();//获取MapperUserMapper userMapper = sqlSession.getMapper(UserMapper.class);//执行Mapper接口方法.UserPO user = userMapper.findUser(1);//打印信息System.err.println(user.getUsername());} finally {//使用完后要记得关闭sqlSession资源if (sqlSession != null) {sqlSession.close();}}}
    • spring 托管:
      • 添加配置

        <import resource="spring-mybatis.xml"/>
  • 插件:
    • 以分页插件为例:

      • 需要 继承 Interceptor

        • @Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),}
          )
          public class PageInterceptor implements Interceptor {
    • interceptorChain.pluginAll(executor) 在configuration 内部注册所有的 plugin
    • 本质就是getSignatureMap 方法,扫描所有注解,对配置的Signature 方法进行 动态代理
    • 代理类就是public class Plugin implements InvocationHandler
    • 执行Plugin 的invoke 会判断该方法是否被代理(signatureMap 里面有没有)
    • 如果有执行 intercept 方法
    • 该方法最后一行执行的proceed 方法,其实就是该方法的invoke 执行
  • 手写TypeHandler:
    • 详见 催收系统CalendarTypeHandler
  • 缓存:
    • 一级缓存:

      • 一级缓存默认开启,SqlSession 级别的
      • 验证:
        • 相同的查询,连续查询两遍,记录查询用时,会发现第二次快得多
        • update、 insert、delete 等语句会触发清除缓存
      • 一级缓存,在存在俩sqlsession 时,可能存在脏数据的情况
        • 比如,sqlsessionA 两次相同查询t 表中间,
        • sqlsessionB 更新了t表数据,
        • sqlsessionA 第二次查询的数据就是可能已被修改的脏数据
    • 二级缓存:
      • 二级缓存默认关闭,SqlSessionFactory 级别的
      • 更不靠谱,开启方式:
  • N+1问题:
    • 存在级联查询(嵌套查询)中

      • 外层查询的一条结果数据,由内层查询获得
      • 外层查询一次,获得结果数N ,就要进行N 次内层查询
        • (官方不鼓励使用,这样产生大量1+N次查询)
    • 由于1+N 问题的性能损耗,可以考虑配合使用 延时加载
    • 官网解释:
  • lazy loading 是怎么做到的?
    • 懒加载在级联查询时用到了,SimpleStatementHandler 里面query结果

    • DefaultResultSetHandler 处理结果
    • handleResultSets -->handleResultSets -->...getRowValue-->createResultObject 
    • 如果有嵌套查询且开启了懒加载 那么会使用代理工厂来处理(代理工厂类型cglib或javasissit类型(默认))
    • 针对某一个属性,当执行
      • 新版本,已经变化:
      • 解释为什么是“或”的关系:lazyLoadTriggerMethods 包含该方法的时候,
        • 说明对象再进行 equals、clone比较,需要所有属性全部查询来才能进行

          • protected Set<String> lazyLoadTriggerMethods =

            • new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
    • 在嵌套查询的时候 get/set 方法会触发 ResultLoaderMap LoadPair load() 方法去查询(我看源代码的理解),
    • 我找到了触发函数lazyLoadTriggerMethods 里面没有get/is 
      • 依赖的是PropertyNamer.isGetter(methodName)

转载于:https://my.oschina.net/u/3847203/blog/3019311

MyBatis 源码分析-技术分享相关推荐

  1. MyBatis 源码分析系列文章合集

    1.简介 我从七月份开始阅读MyBatis源码,并在随后的40天内陆续更新了7篇文章.起初,我只是打算通过博客的形式进行分享.但在写作的过程中,发现要分析的代码太多,以至于文章篇幅特别大.在这7篇文章 ...

  2. 十年老架构师神级推荐,MyBatis源码分析,再也不用为源码担忧了

    十年老架构师神级推荐,MyBatis源码分析,再也不用为源码担忧了 前言 MyBatis是一个优秀的持久层ORM框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL 本身,而不需要花 ...

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

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

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

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

  5. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

  6. MyBatis 源码分析系列文章导读

    1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章.本篇文章从 MyBatis 是什么(what),为什么要使用(why),以及如何使用(how)等三个角度进行了说 ...

  7. MyBatis 源码分析系列文章导读 1

    1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章.本篇文章从 MyBatis 是什么(what),为什么要使用(why),以及如何使用(how)等三个角度进行了说 ...

  8. Mybatis源码分析: MapperMethod功能讲解

    canmengqian </div><!--end: blogTitle 博客的标题和副标题 --> <div id="navigator"> ...

  9. mybatis源码分析之事务管理器

    2019独角兽企业重金招聘Python工程师标准>>> 上一篇:mybatis源码分析之Configuration 主要分析了构建SqlSessionFactory的过程中配置文件的 ...

最新文章

  1. leetcode 454 四数相加
  2. 高级数据结构与算法 | 二叉搜索树(Binary Search Tree)
  3. C语言试题二十八之编写函数function功能是:从字符中删除指定的字符,同一字母的大、小写按不同字符处理。
  4. 中小企业的进步:热爱大数据
  5. 2025年全球5G设备将达到14亿部 但4G仍占主导地位
  6. Html中 table,list等表格 中 js 的 Checkbox全选,反选,单选,获取数据选中行 的写法
  7. [Linux: 编程]如何调试GCC段错误-转
  8. PHP学习笔记 第六讲 PHP数组的创建修改应用
  9. JAVA多线程编程之异步
  10. 计算机辅助设计和制造论文,计算机辅助设计与制造CAD-CAM
  11. linux下ant安装和使用教程,ant安装与简单应用
  12. Lighting build failed. Swarm failed to kick off UE4光照构建失败
  13. 行星轨迹制作_用3ds max制作三维行星运动动画
  14. 玩转视频类信息流广告平台,投放技巧及运营思路看这里
  15. 入门力扣自学笔记180 C++ (题目编号:886)(涂色问题,可以多看看)
  16. 学计算机高考英语听力考试,北京:2018年高考英语听力机考问答
  17. 五子棋-单机游戏-微信小游戏项目开发入门
  18. 【图像修复】基于matlab损坏图像修复【含Matlab源码 731期】
  19. 物理木板过河问题java_抖音捡木板过河
  20. 苹果白屏一直显示苹果_苹果一直白屏怎么办?试试这个办法

热门文章

  1. 敏捷个人第五次练习:个人使命宣言
  2. Windows Vista Upgrade Advisor 1.0
  3. MYSQL从节点延迟问题原因及解决
  4. 【性能优化】 之AWR 报告分析
  5. AndroidStudio Gradle自定义属性xmlns无法识别
  6. android ButterKnife的简单使用
  7. 什么是单页面应用程序
  8. Java并发编程—如何实现线程的超时中断
  9. CMS(Concurrent Mark-Sweep)垃圾回收器
  10. apscheduler 绿色版