在我的博客阅读本文会有更好的阅读体验哦!博客: www.lxiaocode.com
最近看些 MyBatis 的源码,虽说不是很深入但是也对 MyBatis 的查询的执行流程有了整体的了解。本文将会从 selectOne 方法开始一直追溯到 JDBC 的访问数据库,来看一看 MyBatis 到底做了什么,简单的对 MyBatis 的查询接口有个简单的整体的了解。
文本会以 MyBatis 源码为主,不考虑 Spring 的封装。
第零步:MyBatis 查询示例
MyBtais 3 官网:https://mybatis.org/mybatis-3/zh/getting-started.html
在开始阅读源码之前,我们先来复习一下使用 MyBatis 调用查询接口进行查询的方法,下面是从 MyBatis 3 的官方中获取的查询示例:
// 使用 XML 构建 SqlSessionFactory
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 获取 SqlSession 调用 selectOne 查询接口
try (SqlSession session = sqlSessionFactory.openSession()) {
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}
从上面的示例中可以看出,MyBatis 对我们开放的顶层 API 接口是由 SqlSession 接口所提供的。我们接下来就由 SqlSession.selectOne 为起点开始阅读 MyBatis 的查询接口源码。
第一步:SqlSession 顶层接口
1.1 SqlSession 接口
SqlSession 作为 MyBatis 的顶层接口,为我们提供了许多功能。通过这个接口,我们可以执行 SQL 命令、获取映射器和管理事务。本文会聚焦在 selectOne 方法上进行解析。
public interface SqlSession extends Closeable {
<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
// 此处省略其他方法...
}
1.2 DefaultSqlSession 实现类
从类名我们就知道,这是 SqlSeesion 接口的默认实现类。所以说 SelectOne 的默认实现也在这里。
// 这是 SqlSession 的默认实现
// 注意,这个类不是线程安全的
public class DefaultSqlSession implements SqlSession {
// 配置文件
private final Configuration configuration;
// 执行器
private final Executor executor;
private final boolean autoCommit;
private boolean dirty;
private List<Cursor<?>> cursorList;
// 两个构造器
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);
}
// 无参查询接口
@Override
public <T> T selectOne(String statement) {
return this.selectOne(statement, null);
}
// 1. 我们根据示例中调用的查询接口,最后会进入到这个实现方法中来。
// 这个方法非常简单,会直接调用 selectList 方法进行查询
// 然后检查返回是否为一条结果,如果存在多条结果则会抛出异常
@Override
public <T> T selectOne(String statement, Object parameter) {
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size(</