本篇文章主要介绍了笔者根据Mybatis源码,仿写的一个简单查询功能的代码介绍。麻雀虽小五脏俱全,直接看Mybatis吃力的话,不妨从这里开始入手。东西不多,全是干货。如果有问题或者错误,也欢迎大家在评论区指出,一起讨论。
结合项目源码阅读更容易理解
配置及运行机制
- (开发人员实现)传入
数据源和事务工厂,创建环境配置对象Environment - (开发人员实现)创建核心配置类对象
configuration - (开发人员实现)添加mapper到配置类
- 将mapper注册到mybatis中(代码体现在
MapperRegistry类的knownMappers集合,knownMappers集合的key为接口类型,value为代理工厂对象) - 完成接口方法注解中的sql语句的解析,并存入新建的
MappedStatement对象 - 将
MappedStatement对象存入核心配置类configuration中
- 将mapper注册到mybatis中(代码体现在
- (开发人员实现)创建
sqlSessionFactory - (开发人员实现)从
sqlSessionFactory中打开一个sqlSession- 由
Environment中的数据源和事务工厂创建一个事务对象tx - 由
tx创建一个执行器executor - 由
executor和configuration创建一个默认的sqlSession
- 由
- (开发人员实现)从
sqlSession中获取指定类型的mappersqlSession去configuration查找mapper,configuration去MapperRegistry类中查找mapper- 在
MapperRegistry类中,通过key从knownMappers集合中获取代理工厂对象mapperProxyFactory - 通过代理工厂对象
mapperProxyFactory,创建mapper接口的实例并返回(此处使用了JDK动态代理,MapperProxy类为动态代理的调用处理类)
- (开发人员实现)调用mapper的指定方法
- 调用mapper指定方法,
MapperProxy类中的invoke方法会触发 MapperProxy类中的invoke方法调用内部静态类PlainMethodInvoker的invoke方法,并创建MapperMethod对象的实例PlainMethodInvoker的invoke方法调用MapperMethod实例的execute方法,传入sqlSession和查询参数execute方法调用sqlSession的查询方法,传入完整的方法名和查询参数sqlSession的查询方法通过方法名,从configuration中获取MappedStatement对象- 调用
executor的查询方法,并传入MappedStatement对象和查询参数- 在
executor的查询方法中,创建StatementHandler的实例handler(此时将解析过的sql语句等信息存入实例) - 获取数据库连接
connection(通过connection的prepareStatement方法设置sql语句),并生成查询用的statement对象(期间会设置查询参数相关信息) - 调用
handler的query(执行查询),接收到返回结果集后,使用ResultSetHandler的实例对结果集进行处理 - 返回查询结果
- 在
- 调用mapper指定方法,
项目目录结构及说明
self-mybatis(简化版mybatis,主要用于学习mybatis的加载机制和执行原理)
└── java
└── org.self.mybatis
├── annotations -- 注解相关的文件夹
| └── SelfSelect -- mapper接口中,方法上配置sql语句时,使用的注解
├── binding -- 绑定相关的文件夹
| ├── MapperMethod -- mapper中的方法调用(JDK动态代理调用)及处理
| ├── MapperProxy -- JDK动态代理的调用处理类(代理后,执行时调用MapperMethod)
| ├── MapperProxyFactory -- 为mapper接口动态代理的工厂(注册mapper时调用)
| └── MapperRegistry -- mapper注册器
├── builder -- builder相关的文件夹
| └── annotation -- 注解配置的builder的文件夹
| ├── MapperAnnotationBuilder -- 注解配置sql的mapper的builder
| └── MethodResolver -- mapper接口中的方法解析
├── exceptions -- 异常相关的文件夹
| └── PersistenceException -- 持久化异常
├── executor -- 执行器相关的文件夹
| ├── parameter -- 查询参数相关的文件夹
| | ├── DefaultParameterHandler -- 默认参数处理器
| | └── ParameterHandler -- 参数处理器接口
| ├── resultset -- 查询结果集相关的文件夹
| | ├── DefaultResultSetHandler -- 默认结果集处理器
| | └── ResultSetHandler -- 结果集处理器接口
| ├── statement -- 查询statement相关的文件夹
| | ├── SelfStatementHandler -- 自定义statement处理器,用来创建statement(mybatis中有多个,此处为自定义的)
| | └── StatementHandler -- statement处理器接口
| ├── Executor -- 执行器接口
| └── SelfExecutor -- 自定义执行器,用来执行数据库或缓存的查询(mybatis中有多个,此处为自定义的)
├── mapping -- 映射相关的文件夹
| ├── BoundSql -- 存储sql和查询参数的对象(类中属性被简化过)
| ├── Environment -- 环境配置(主要存储数据源和事务工厂对象)
| ├── MappedStatement -- 用来存储生成statement对象时,需要的信息
| └── SqlSource -- 获取(生成)BoundSql的接口
├── session -- 数据库session相关的文件夹
| └── defaults -- 默认的session相关的文件夹
| | ├── DefaultSqlSession -- 默认的sqlSession
| | ├── DefaultSqlSessionFactory -- 默认的sqlSession工厂
| | └── SqlSessionFactory -- sqlSession工厂的接口,用来创建sqlSession
| ├── Configuration -- 记录mybatis主要配置的核心配置类
| ├── ExecutorType -- 执行器类型枚举类
| ├── SqlSession -- sqlSession(提供查询、获取mapper、获取数据库连接等操作)
| └── TransactionIsolationLevel -- 事务隔离等级枚举类
└── transaction -- 事务相关的文件夹
├── managed -- 主事务(默认事务)相关的文件夹
| ├── ManagedTransaction -- 主事务(默认事务,未指定事务时使用)
| └── ManagedTransactionFactory -- 主事务(默认事务)工厂
├── JdbcTransaction -- Jdbc事务
├── JdbcTransactionFactory -- Jdbc事务工厂
├── Transaction -- 事务接口(创建数据库连接,提交事务,事务回滚等方法)
├── TransactionException -- 事务异常
└── TransactionFactory -- 事务工厂接口(创建事务)