画布 1
ORM
  ORM
    什么是ORM
    JDBC的缺点
      频繁创建数据库连接,浪费连接资源,不易维护
      SQL语句存在硬编码，不易维护
      结果集处理过程繁琐
  Mybatis
    什么是Mybatis
    为什么说Mybatis是半ORM框架
    Mybatis优缺点
      优点
        消除了JDBC硬编码，提高了应用的扩展性
        自定义SQL和对象持久化关系，带来了灵活性
        SQL和对象持久化关系都在配置里，解除了SQL与程序之间的耦合性
      缺点
        配置繁琐
    Mybatis适用场景
      功能复杂的应用
      考虑SQL优化的应用
    Mybatis架构
      Configuration
      SqlSession
      Executor
      StatementHandler
        ParameterHandler
        TypeHandler
        ResultSetHandler
    Mybatis执行流程
      1. 配置解析
      2. 使用配置环境信息构建SqlSessionFactory工厂
      3. 使用SqlSessionFactory创建SqlSession会话
      4. 使用SqlSession获取用户需要的Mapper类
      5. 使用MapperProxy执行目标方法
      6. Executor调用StatementHandler对Statement做出处理(包括参数处理，执行，结果集处理)。
      7. StatementHandler调用ParameterHandler装配SQL参数并执行,最后使用ResultSetHandler封装结果集返回。
    Executor
      Executor的类型
        SimpleExecutor
        ReuseExecutor
        BatchExecutor
    Mybatis延迟加载
      什么是延迟加载
      延迟加载原理
    ${} 和 #{}的区别
      #{} 把传入的参数当做字符串，会给参数加上引号；${} 是将传入的参数直接显示在SQL中
      #{} 属于占位符，需要预编译；${}属于拼接符，需要进行字符串拼接
      #{} 可以在很大程度上预防SQL注入；${} 则不能防止SQL注入
    Mybatis 模糊查询LIKE怎么写
      SELECT * FROM table WHERE name LIKE '%${name}%' (有注入风险)
      SELECT * FROM table WHERE name LIKE "%"#{name}"%"
      SELECT * FROM table WHERE name LIKE CONCAT('%',#{name},'%')
      Bind标签
    Mybatis如何获取生成的主键
    Mybatis动态SQL
    Mybatis插件
      插件类型
        Executor
        StatementHandler
        ParameterHandler
        ResultSetHandler
      插件原理
    Mybatis查询缓存
      一级缓存
        一级缓存的原理
        一级缓存失效的方法
          如果SQL相同，但是SQL的条件或参数不同，缓存会失效
          在两次查询操作中间，如果进行了增删改操作，会清空本地缓存
          不同的SqlSession，缓存会失效
          手动清空SqlSession的缓存
      二级缓存
        二级缓存的原理
      Mybatis缓存的缺点
        Mybatis缓存设计缺陷
        容易引起脏读
作者: qsjzwithguang19forever
作者微信: yg1446125917
作者邮箱: 2196927727@qq.com
作者github: github.com/guang19
本xmind归属于qsjzwithguang19forever的开源项目:framework-learning。
framework-learning旨在为Java方向的开发者提供较为全面，通俗的知识梳理。
项目地址: github.com/guang19/framework-learning
如若转载，请声明来源。
Object Relational Mapping 对象关系映射。它是一种解决数据库与简单对象(entity)之间关系映射的技术。
简单理解: ORM通过简单对象(entity) 与 数据库之间的映射关系，将描述对象持久化到数据库中。
Mybatis是一款优秀的轻量级的半ORM框架。
Mybatis最大的优点就是无需像JDBC一样采用硬编码的方式进行持久化操作，它允许我们定制SQL和对象与数据库之间的高级映射关系，极大的提高了持久化操作的灵活性。
与Hibernate不同，Hibernate属于全自动ORM框架，无需手写SQL，且能够自动建立对象与数据库之间的映射关系，很方便。但无需手写SQL也就意味着SQL优化方面可能不如Mybatis那么出色。
Mybatis则属于半自动ORM框架，因为Mybatis仅仅给我们省去了JDBC硬编码的形式，但是在定义SQL和建立对象持久化关系方面，仍然给了我们很大自由，它相对Hibernate更加灵活，扩展性更强。
虽然Mybatis具有很强的灵活性，但在建立对象和持久化关系，定义SQL方面还是需要我们进行手动配置，不过我个人认为这也不算是它的缺点，毕竟配置也带了稳定。
Mybatis足够的灵活，这保证了它能够面对较为复杂的应用场景。
SQL优化是一个很常见的问题，Mybatis允许我们自己编写SQL，这样一来就可以轻松的更新和优化SQL了。
Configuration可以说是贯穿整个Mybatis生命周期的一个核心配置组件，它存储着Mybatis所有需要的属性和组件。
从解析阶段开始，到获取Mapper，都需要Configuration。
SqlSession是Mybatis最顶级的API接口，它封装了Sql的增删查改功能，但最终还是交由Executor去执行逻辑。
Executor执行器，是Mybatis的核心组件之一，它负责调度StatementHandler来维护和执行SQL。
StatementHandler负责JDBC的statement的操作，如SQL入参，执行SQL，封装结果集。
ParameterHandler负责将用户传递的参数转换成statement所需的参数。
TypeHandler负责Java数据类型与JDBC数据类型的转换。
ResultSetHandler负责处理statement执行后返回的结果集。
由XML解析器解析配置文件(总配置文件，mapper文件),并将解析的结果保存到Configuration中.
SqlSessionFactory提供了构建SqlSession的多种方式，可以指定Executor的类型和事务隔离级别等。
SqlSessionFactory创建SqlSession后，其实是创建的DefaultSqlSession，它包含了Mybatis的环境配置Configuration和Executor执行器。
Mybatis底层是使用了jdk动态代理来实现目标Mapper的执行的，获取Mapper实际上是获取Mapper的代理类。
实际上最终是Executor调度StatementHandler执行statement。
简单执行器。 每次执行SQL就开启一个statement，用完后就关闭掉。
可重用的执行器。每次执行SQL先去缓存(Map)中找SQL对应的statement，如果不存在就新创建statement，用完后并不关闭，而是放入Map缓存中，以待下次使用。
批处理执行器。执行SQL时，会将statement添加到批处理中，等到最终executeBatch时，一起执行。
延迟加载又称按需加载，即在关联查询中(一对一或一对多)，如果指定了延迟加载，那么并不会一次就把对象关联的数据查出来，而是等到对象需要使用关联的数据时才会进行查询。
Mybatis的底层原理是ResultSetHandler在封装结果时，判断对象的属性是否有关联查询(嵌套查询)，如果有，则使用动态代理创建该对象作为结果，当对象需要使用它的某个属性时，比如a调用getB方法，那么getB方法就会进入代理方法，如果getB为空，就查询B，并setB，这样就可以获取到a的B属性了。
假设有2条SQL如下:
1. SELECT * FROM table WHERE id =${id};
2. SELECT * FROM table WHERE id = #{id};
如果传入的参数为 1 ,
那么第一条SQL会被拼接成:
SELECT * FROM table WHERE id = 1;
第二条SQL会被编译成:
SELECT * FROM table WHERE id = "1";
假如有一条SQL:
SELECT * FROM table WHERE id = ${id}
假设传入的id为: 1 OR 1 = 1 ,那么字符串拼接后,SQL为:
SELECT * FROM table WHERE id = 1 OR 1 = 1;
这条SQL无论如何都会执行成功。
如果将 ${id} 改为 #{id},那么经过预编译后，SQL为:
SELECT * FROM table WHERE id = "1 OR 1 = 1";
可以看到: #{} 是将参数作为一个字符串为条件的，这样就可以避免 OR 生效，防止SQL注入。
Mybatis有一个KeyGenerator接口，这个接口专门用于获取数据库生成的主键。但其核心原理还是使用的JDBC 的 API : Statement的 getGeneratedKeys 方法获取的。
Mybatis允许我们在mapper文件内，以标签的形式编写动态SQL，用于逻辑判断和SQL拼接等功能。
Mybatis动态标签有: trim / where / set / if / choose / otherwise / bind / foreach 等，实际上Mybatis的动态标签是依赖于OGNL的。
Mybatis允许我们编写插件对它核心的组件做出扩展。
Mybatis底层实际上是使用jdk动态代理包装后的组件带替它原生的组件。
当执行这些组件的方法时，就会执行Interceptor的intercept方法。当然，只是当执行我们指定要拦截的方法时，才会执行intercept方法。
Mybatis查询缓存可以分为一级缓存和二级缓存。
一级缓存又称本地缓存，它属于SqlSession级别的缓存，默认是开启的。每个SqlSession都有自己的缓存。
同一个SqlSession查询到的数据都会放入它自己的缓存中，如果之后需要获取相同的数据，那么会先从缓存中查找，如果没有才会去查询数据库，这样就降低了数据库的压力。
对于BaseExecutor来说，它内部维护了一个叫localCache的PerpetualCache对象。PerpetualCache实现了Cache接口，它内部使用HashMap进行缓存。
所以可以简单理解为Mybatis的一级缓存是由HashMap存储的。
二级缓存又称全局缓存，它属于mapper级别的缓存,默认是关闭的，需要指定配置和标签才会开启。
多个SqlSession操作同一个Mapper是可以共享一个二级缓存的，但是要求Sql会话必须属于同一个Mapper。
Mybatis二级缓存的Executor使用的是CachingExecutor，在原生的Executor执行查询操作之前，它会先从二级缓存中查询，如果查询不到才会从一级缓存或数据库中查询。
Mybatis的一级缓存是使用HashMap实现的，并没有指定容量限制，虽然可以提高查询效率，但是设计上还有所欠缺。
Mybatis的缓存是属于Java进程内的缓存，在分布式环境下，缓存的不一致，很容易引起数据的脏读。
建议还是使用第三方容器，如Redis或memcached存储缓存。