调用API
和使用Mapper 代理
将主配置文件内容解析封装到 configuration,将SQL的配置信息加载成为一个mappedstatement对象,存储在内存中
调用MyBatis的api,传入sql的Id 和 参数对象,将请求传递给请求处理层进行处理
返回处理结果
简单来说 MyBatis 就是对我们 jdbc 的一个封装,我们使用jdbc 的时候,大值的流程步骤如下
// 加载配置文件,获取到输入流
InputStream resourceAsStream = Resources.getResourceAsStream("configuration.xml");
// 开始初始化
// 将获取到的文件输入流通过 SqlSessionFactoryBuilder 进行构建,此时是真正的初始化过程
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 进入 build 方法中
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
// 可以看到下面几行代码
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
// 通过 XMLConfigBuilder 将配置文件中的信息读取出来,然后在通过 parser.parse() 进行解析
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
}
// XMLConfigBuilder 进行读取的时候会给一些必要数据进行初始化,包括后面用到的 parsed ,表示是否已经被解析过了
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each MapperConfigParser can only be used once.");
}
// 标记已经解析
parsed = true;
// 这个方法下会将 xml 文件中的setting,properties,typeAliases进行读取,最重要的是对 mappers 标签进行解析,将所有的mapper.xml中的select标签 insert等封装成一个mappedstatement对象,再把mappedstatement 封装到 configuration 中
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
// build 就是对 configuration 进行初始化的过程
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
// 因此在初始化这一步骤我们已经拿到了 configuration 和 封装好的mappedstatement
// 获取到 sqlSession和创建executor,一般我们使用的 simpleExecutor,除此之外还有batchExecutor
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过拿到的 SqlSession去执行sql语句,sql语句的执行器是上一步获取到的 simpleExecutor 来进行操作的
// executor 首先会先尝试在一级缓存中获取数据
// 具体的操作语句是使用 StatementHandler 进行完成的
// 首先根据StatementHandler获取到数据库的连接信息,然后使用
List<Object> objects = sqlSession.selectList("");
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
// 创建一级缓存 key
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
// 查询操作
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
// 具体的 query 操作
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
....
try {
queryStack++;
// localCache.getObject(key) 根据 key 获取到一级缓存的数据
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 查询数据库
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
}
....
return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
// 直接看 doQuery 方法,点击选择 simpleExecutor
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
}
// 创建 StatementHandler ,通过 prepareStatement 给 StatementHandler 设置数据库连接参数
// 然后交由 StatementHandler 去具体的执行sql
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
return Collections.emptyList();
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection);
handler.parameterize(stmt);
return stmt;
}