个人学习GitHub开源项目系列 Mybatis源码篇
Github Link: https://github.com/mybatis/mybatis-3
Mybatis简介
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录
MyBatis框架主要完成的是以下2件事情:
- 根据JDBC规范建立与数据库的连接。
- 通过反射打通Java对象与数据库参数交互之间相互转换的关系。
MyBatis框架是一种典型的交互式框架,先准备好交互的必要条件,然后构建一个交互的环境,在交互环境中划分会话,在会话中与数据库进行交互数据。
源码环境准备
1.下载源码 git clone https://github.com/mybatis/mybatis-3.git
2.在对应文件夹执行 mvn clean install
3.将项目导入IDE 效果如图
Mybatis源码解析
Mybatis主要的类
- Configuration MyBatis所有的配置信息都维持在Configuration对象之中。
- SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
- Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
- StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
- ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数
- ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
- TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换
- MappedStatement MappedStatement维护了一条<select|update|delete|insert>节点的封装,
- SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
- BoundSql 表示动态生成的SQL语句以及相应的参数信息
图片引用自https://blog.csdn.net/luanlouis/article/details/40422941
1. 接口层 (SqlSession)和数据库交互的顶层API
Mybatis和数据库交互的几种方式
(1)传统的API模式(基本不使用)
创建一个和数据库打交道的SqlSession对象,然后根据Statement Id 和参数来操作数据库,这种方式固然很简单和实用,但是它不符合面向对象语言的概念和面向接口编程的编程习惯。
(2)Mapper接口并与XML配合模式
当需要自定数据库操作方法时,需要添加方法并在XML文件中添加相应的SQL。id值为Mapper 接口中的方法名称,parameterType 值表示Mapper 对应方法的入参类型,而resultMap 值则对应了Mapper 接口表示的返回值类型或者返回结果集的元素类型。
@Mapper
public interface UserMapper {
List<User> getAll();
User getUserInfoByOpenId(String openid);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="XXX.mapper.UserMapper">
<resultMap id="BaseResultMap"
type="XXX.model.User">
...
...
</resultMap>
<select id="getAll" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user_
</select>
<select id="getUserInfoByOpenId" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user_
where openid = #{openid,jdbcType=VARCHAR}
</select>
</mapper>
(3)Mapper接口注解方式
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user_")
List<UserEntity> getAll();
@Select("SELECT * FROM user_ WHERE openid = #{openid}")
UserEntity getUserByOpenId(@Param("openid") String openid);
}
2. 数据处理层 Mybatis核心
核心功能:
(1)通过参数映射解析将传入参数构建动态的SQL语句
(2)SQL语句通过Executor执行
(3)封装查询结果转化为Java type List<E>
ParameterHandler
负责对用户传递的参数转换成JDBC Statement 所需要的参数.参数映射指的是对于java 数据类型和jdbc数据类型之间的转换,在查询阶段,我们要将java类型的数据,转换成jdbc类型的数据,通过 preparedStatement.setXXX() 来设值;
SqlSource
根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中。
TypeHandler
负责java数据类型和jdbc数据类型之间的映射和转换,对Statement对象设置特定参数,对Statement返回的结果集resultSet取出特定列,涵盖各种数据类型如下如所示
StatementHandler
封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。Statement包下多个类对StatementHandler完成了实现。
PreparedStatementHandler
负责对用户传递的参数转换成JDBC Statement 所需要的参数
Executor
MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护。Executor接口含方法如下
Executor整体执行流程如下
ResultSetHandler
负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
Mybatis SqlSession常规流程
1、 mybatis配置
mybatis-config.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
SqlSession sqlSession = factory.openSession();
4、为SqlSession传递一个配置的Sql语句的Statement Id和参数然后返回结果
List<User> result = sqlSession.selectList("com.peter.mybatis.dao.UserMapper.selectById",params);
5、MyBatis在初始化的时候,会将MyBatis的配置信息全部加载到内存中,使用org.apache.ibatis.session.Configuration实例来维护,使用者可以使用sqlSession.getConfiguration()方法来获取。加载到内存中会生成一个对应的MappedStatement对象,然后该对象会以key="com.peter.mybatis.dao.UserMapper.selectById" ,value为MappedStatement对象的形式维护到Configuration的一个Map中。当以后需要使用的时候,只需要通过Id值来获取就可以了。
6、SqlSession根据Statement ID, 在mybatis配置对象Configuration中获取到对应的MappedStatement对象,然后调用mybatis执行器来执行具体的操作。
7、MyBatis执行器Executor根据SqlSession传递的参数执行query()方法
8、Executor执行过程中(会为查询创建缓存,以提高性能),会创建一个StatementHandler对象,然后将必要的参数传递给StatementHandler,PreparedStatement类型的对象在创建的过程中,是使用SQL语句字符串会包含若干个? 占位符,我们其后再用传入的参数对占位符进行设值
9、StatementHandler通过List<E> query(Statement statement, ResultHandler resultHandler)方法来完成执行Statement,和将Statement对象返回的resultSet封装成List
Mybatis中用到的设计模式总结
-
Builder模式,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;
-
工厂模式,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;
-
单例模式,例如ErrorContext和LogFactory;
-
代理模式,Mybatis实现的核心,比如MapperProxy、ConnectionLogger,用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;
-
组合模式,例如SqlNode和各个子类ChooseSqlNode等;
-
模板方法模式,例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;
-
适配器模式,例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;
-
装饰者模式,例如Cache包中的cache.decorators子包中等各个装饰者的实现;
-
迭代器模式,例如迭代器模式PropertyTokenizer;