# lite-mybatis **Repository Path**: shawnisacoder/lite-mybatis ## Basic Information - **Project Name**: lite-mybatis - **Description**: 基于Mybatis的思路仿写的轻量的持久化框架 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-02-25 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Lite-Mybatis 基于Mybatis的思路仿写的轻量的持久化框架。主要目的是通过该框架学习`mybatis`的源码。 ## 设计思路 * [1. 原生JDBC所存在的问题](doc/01.The_Problems_of_Native_JDBC.md) * [2. XML配置文件与资源加载](doc/02.XML_and_Resources.md) * [3. 解析配置文件](doc/03.Configuration_and_MappedStatment.md) * [4. 构建框架主体](doc/04.SqlSessionFactoryBuilder_SqlSessionFactory_SqlSession.md) * [5. 数据库会话与执行器](doc/05.SqlSession_and_Executor.md) * [6. 执行器的实现](doc/06.The_Implementation_of_Executor.md) * [7. Mapper代理](doc/07.Mapper_Proxy.md) ## 重点问题 ### 1. Mybatis动态sql是做什么的?都有哪些动态sql?简述一下动态sql的执行原理? 当我们需要根据参数条件来执行不同的SQL时,就可以使用**动态SQL**。常用的动态SQL包括``、`if`、 `foreach`等等。 `mybatis`中,提供了SqlNode接口用于实现动态SQL。其定义如下: ```java public interface SqlNode { boolean apply(DynamicContext context); } ``` 常见的实现类包括:`ChooseSqlNode`、`ForEachSqlNode`、`IfSqlNode`等。当需要解析动态SQL时, `mybatis`会根据我们所使用的动态SQL标签将SQL拆分为一段一段的`SqlNode`,并组织好对应的上下文环境 `DynamicContext`。最后通过`SqlNode#apply(DynamicContext)`方法来判断当前SQL片段是否能够应用。 由此来获取到完整的SQL。之后的操作就跟使用普通SQL语句一致了。 ### 2. Mybatis是否支持延迟加载?如果支持,它的实现原理是什么? `mybatis`支持在``和``标签上实现延迟加载。其实现原理是通过**动态代理**生成结果集对象。 当用户执行`getter`方法时,代理类判断当前属性是否已经加载过。若没有加载,此时再执行对应的SQL语句。 ### 3. Mybatis都有哪些Executor执行器?它们之间的区别是什么? 根据源码中`Configuration#newExecutor(Transaction, ExecutorType)`方法可以得知,常用的有4种实现: * `BatchExecutor`:主要用于批量操作; * `ReuseExecutor`:其会以SQL语句为Key缓存Statement对象; * `SimpleExecutor`:最常见的`Executor`,没有做额外优化动作; * `CachingExecutor`:开启二级缓存之后所使用的`Executor`; ### 4. 简述下Mybatis的一级、二级缓存 * 一级缓存: * 存储结构:核心类为`PerpetualCache`,本质上是通过一个HashMap进行缓存数据的存储,其Key的组成较为复杂,由`MappedStatement`、执行参数、`RowBounds`和`BoundSql`构成 * 范围:其作用范围为`SqlSession` * 失效场景:当`SqlSession`执行"增删改"操作并提交事务时,或是`SqlSession`主动调用`clearCache()时失效` * 二级缓存: * 存储结构:默认情况下仍然使用的是`PerpetualCache`; * 范围:其作用范围为`namespace`,多个`SqlSession`可以共享二级缓存; * 失效场景:当`SqlSession`执行"增删改"操作并提交事务时会被清空。同时可以通过配置`MappedStatement`的`useCache`和`flushCache` 参数来进行额外的控制; ### 5. 简述Mybatis的插件运行原理,以及如何编写一个插件 `mybatis`插件体系可以对其四大对象:`Executor`、`StatementHandler`、`ParameterHandler`和`ResultSetHandler`进行增强。 其核心原理为**动态代理**。这四大对象创建时,会通过`interceptorChain.pluginAll(Object)`方法来进行拦截,从而再通过每个插件对象的 `plugin(Object)`方法来实现额外的逻辑。 要编写自定义的插件,需要实现`Interceptor`接口。该接口提供了3个方法需要实现: * intercept(Object):核心方法,用于增强指定对象; * plugin(Object):通过当前拦截器生成代理对象,并将代理对象添加到拦截器链中传递给下一个拦截器; * setProperties(Properties):传递插件的配置参数 除此之外,还需要添加对应的注解,如下: ```java @Intercepts({ @Signature( type = StatementHandler.class, // 指定拦截的对象 method = "prepare", // 指定拦截的方法名 args = { Connection.class, Integer.class } // 考虑到方法重载的问题,还需要指定方法参数才能确定到所要拦截的方法 ) }) public class MyInterceptor implements Interceptor { // ... } ```