Mybatis源码学习-笔记
参考资料:https://www.open-open.com/ppt/e2d62f17112544eb93748c5dbe92d58c.html
疑问待解决:
spring-mybatis中SqlSessionTemplate
怎么执行sql的
一.Mybatis访问数据库步骤(非常重要 屡着源代码多看几遍)
1.读取配置文件(配置文件要包含数据库连接信息以及mapper文件地址)
2.创建SqlSessionFactoryBuild对象
3.通过SqlSessionFactoryBuild创建SqlSessionFactory工厂
4.通过SqlSessionFactory创建SqlSession对象
5.为DAO接口生成代理类
6.动态代理回调SqlSession某方法
7. SqlSession将要操作的方法转发给Executor(并组装好cacheKey)(paramHandle运用插件的原理)
11.把数据返回给调用者
8.去查询cacheKey是否命中,如果命中直接返回,如果没有命中
9.Executor交给StatementHandler去执行(里面有个statement.execute(sql)真正执行sql的操作-JDBC访问数据库操作数据)代理模式
10. Executor通过反射将数据封装POJO返回给sqlsession(resultParamHandle运用插件的原理)
11.把数据返回给调用者
写dao实现类怎么找到对应sql
sqlsession.selectlsit(namespace+sqlId);
不写dao实现类怎么找到对应的sql呢(怎么从dao-mapper)
class object = sqlseesion.getMapper(class);
object为mapper的代理对象
dafulatSqlSession->getMapper方法->mapperRegistry.getMapper->mapperProxyFactory.newInstance->Proxy.newProxyInstance(生成代理对象)
MapperProxy->都会去执行invoke方法->invoke里面都会执行mapperMethod.execute(this.sqlSession, args)
二.生命周期
SqlSessionFactoryBuilder 对象用于构建 SqlSessionFactory,只要构建好, SqlSessionFactoryBuilder 对象就可以丢弃了。SqlSessionFactory 是一个工厂类,一旦被创建 就应该在应用运行期间一直存在,不应该丢弃或重建。SqlSession 不是线程安全的,所以不 应被多线程共享。官方推荐的使用方式是有按需创建,用完即销毁。因此,以上步骤中,第 1、2 和第 3 步只需执行一次。第 4 和第 5 步需要进行多次创建
三.MyBatis VS Hibernate
Hibernate 可自动生成 SQL,降低使用成本。但同时也要意识到,这样做也是有代价的, 会损失灵活性。比如,如果当我们需要手动优化 SQL 时,会发现很难改变 Hibernate 自动生 成的 SQL。因此对于 Hibernate 来说,它适用于一些需求比较稳定,变化比较小的项目,譬 如 OA、CRM 等。(无法手动优化sql)
MyBatis 需要手动维护 SQL,这会增加使用成本。但同时,使用者可 灵活控制 SQL 的行为,这为改动和优化 SQL 提供了便利性。所以 MyBatis 适合应用在一些 需要快速迭代,需求变化大的项目中.
除此之外,MyBatis 还提供了插件机制,使用者可以按需定制插件。这也是 MyBatis 灵活性的一个体现。
四.在 Spring 中使用 MyBatis
数据源配置 到 Spring 配置文件中。配置完数据源,接下来配置 SqlSessionFactory。再接下来是配置 MapperScannerConfigurer,这个类用于 扫描某个包下的数据访问接口,并将这些接口注册到 Spring 容器中。这样,我们就可以在其 他的 bean 中注入 Dao 接口的实现类,无需再从 SqlSession 中获取接口实现类
延迟加载原理
使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

五:插件原理
Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。
实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
Mybatis分页插件安全性问题:
PageHelper 方法使用了静态的 ThreadLocal 参数,分页参数和线程是绑定的。
只要你可以保证在 PageHelper 方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为 PageHelper 在 finally 代码段中自动清除了 ThreadLocal 存储的对象。
如果代码在进入 Executor 前发生异常,就会导致线程不可用,这属于人为的 Bug(例如接口方法和 XML 中的不匹配,导致找不到 MappedStatement 时), 这种情况由于线程不可用,也不会导致 ThreadLocal 参数被错误的使用。

浙公网安备 33010602011771号