了解MyBatis工作原理先了解这几个类的作用:
Configuration MyBatis所有的配置信息都保存在Configuration对象之中,配置文件中的大部分配置都会存储到该类中
SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互时的会话,完成必要数据库增删改查功能
Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数等
ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所对应的数据类型
ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
TypeHandler 使用Java反射技术完成JavaBean对象到数据库参数之间的相互转换
SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
BoundSql 表示动态生成的SQL语句以及相应的参数信息
MyBatis层次结构图:
创建SqlSession的工程源码解读:
// 这是一个创建SqlSession的过程
// 将配置文件以流的形式引入
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建SqlSessionFactory
SqlSessionFactoryBuilder sessionFactory = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = sessionFactory.build(inputStream);
// 创建sqlSession
SqlSession session = factory.openSession();
- 了解一下SqlSessionFactory创建过程及作用:
/**
* SqlSessionFactoryBuilder类中只有9个重写的build方法,
* 我删除了方法体中的内容、
*/
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {}
public SqlSessionFactory build(Reader reader, String environment) {}
public SqlSessionFactory build(Reader reader, Properties properties) {}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {}
// 以流的形式将配置文件引入
public SqlSessionFactory build(InputStream inputStream) {}
public SqlSessionFactory build(InputStream inputStream, String environment) {}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {}
// 将主配置文件加载
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {}
// 将主配置文件引入的其他配置文件加载
public SqlSessionFactory build(Configuration config) {}
}
- 接下来看一下SqlSession的创建过程:
// SqlSession和核心类Executor挂钩
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
public DefaultSqlSession(Configuration configuration, Executor executor) {
this(configuration, executor, false);
}
- SqlSession都是通过Executor来执行的,所以Executor是MyBatis的核心。
- Executor并没有真正的去执行数据库操作,而是交由StatementHanlder来处理的。
public interface StatementHandler {
//从Connection中获取Stament对象
Statement prepare(Connection connection) throws SQLException;
//设置预处理参数
void parameterize(Statement statement) throws SQLException;
//调用批量操作
void batch(Statement statement) throws SQLException;
//更新操作
int update(Statement statement) throws SQLException;
//查询操作
<E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
//获取执行SQL语句的封装类BoundSql
BoundSql getBoundSql();
//参数处理器
ParameterHandler getParameterHandler();
}
- 接下来就是使用ParameterHandler来设置参数,getParameterObject()是获取参数的,而setParameters()是设置参数的
,相当于对一条sql所有的参数都执行ps.setXXX(value);
/**
* A parameter handler sets the parameters of the {@code PreparedStatement}
*
* @author Clinton Begin
*/
public interface ParameterHandler {
Object getParameterObject();
void setParameters(PreparedStatement ps)
throws SQLException;
}
- 从mybatis接收参数到mysql存储数据,都会用到typeHandler类型处理器。这也就是从JavaType->JdbcType的转化过程。由于mybatis初始时已经内置大部分基础类型转化的TypeHandler,已经足够我们平常的简单应用开发了,所以大多数情况下并不需要我们自己去定义类型转换器。
public TypeHandlerRegistry() {
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
.......
}
- 这样就生成了原生的JDBC操作代码。
- 再看ResultSetHandler负责的任务:
(1)处理Statement执行后产生的结果集,生成结果列表
(2)处理存储过程执行后的输出参数
/**
* @author Clinton Begin
*/
public interface ResultSetHandler {
// 处理执行statement后的结果集
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
// 执行存储过程执行后的输出参数
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
void handleOutputParameters(CallableStatement cs) throws SQLException;
}