MyBatis源码分析是一个系列,旨在深入了解MyBatis执行流程以及原理。本篇我们先大体的看下MyBatis整个的执行流程,对MyBatis整体有个了解,然后我们在找几个主题深入的去讨论,比如缓存、连接池等,希望通过MyBatis系列,对你有所帮助,那么我们开始吧!
首先每一个框架都会有一个入口,让我们可以很容易的拿来即用,同样也可以沿着入口,了解这个框架的整体流程,然后在深扒底层的原理细节。MyBatis官网提供给我们如何在项目中使用它。1
2
3
4
5
6
7
8
9
10
11String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
} finally {
session.close();
}
上述代码是一个典型的MyBatis查询语句,那我们从这几句话开始我们的分析。
首先创建了一个SqlSessionFactory
,也就是MyBatis的入口。它的主要功能就是创建SqlSession
。
在SqlSessionFactyoryBuilder
类中根据提供的XML配置,创建了一个DefaultSqlSessionFactory
的实例
通过SqlSessionFactory
打开一个SqlSession
,首先我们去看下SqlSession
接口的描述
1 | SqlSession用于处理MyBatis的主Java接口。 |
SqlSession的方法都是常用的增删改查,事务的回滚提交,以及缓存等,该接口是MyBatis操作的核心。
那我们去看下刚才代码中创建DefaultSqlSessionFactory
实例是如何打开一个SqlSession
1 | private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { |
方法返回一个DefaultSqlSession
实例,一起创建还有TransactionFactory
和Executor
实例,跟每个SqlSession绑定。
ExcutorType
可以通过XML配置中的setting.defaultExecutorType
来自定义。如果没有在配置中指定,会设置一个默认值,在方法XMLConfigBuilder.settingsElement()
中可以找到相应的代码。
TransactionFactory
的创建是通过Environment.getTransactionFactory()
方法来实现的。同样也可以使用xml中setting.transactionManager
进行配置配置的。Environment
的实例化可以在XMLConfigBuilder.environmentsElement()
找到,根据提供的type对应的Class对象反射创建一个TransactionFactory
。
1 | private TransactionFactory transactionManagerElement(XNode context) throws Exception { |
XML中setting.transactionManager
的配置是JDBC
,在TypeAliasRegistry.resolveAlias
方法中解析到指定的类。
其中使用的TYPE_ALIASES
是一个Map
,在TypeAliasRegistry
的构造函数中已经初始化了一部分数据,但是我们并没有看到JDBC
的key,我们在继续深入查看调用TypeAliasRegistry.registerAlias
方法的地方,可以看到Configuration
的构造函数中设置了该值:
1 | typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class); |
所以上面TransactionFactory
实例了一个JdbcTransactionFactory
的对象,并根据数据源、事务隔离级别、是否自动提交事务,创建了一个Transaction
实例,Transaction
包装了数据库连接,处理连接生命周期,包括:创建,准备,提交/回滚和关闭。
接下来创建了一个Executor
:
1 | public Executor newExecutor(Transaction transaction, ExecutorType executorType) { |
cacheEnabled
可以通过xml中settings.cacheEnabled
配置,默认为true,可以在XMLConfigBuilder.settingsElement
方法中找到相应代码:
1 | configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true)); |
创建了一个CachingExecutor
实例。最后将三个参数组合创建了一个DefaultSqlSession
实例。
然后我们就走到真正的查询是怎么进行的了,那我们继续看代码,我们找一个最简单的selectOne
去看下。
1 | public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { |
MappedStatement
是读取在xml中配置的Mapper信息,然后解析里面的insert/update/delete/select语句创建的实例。具体实现代码可以在XMLConfigBuilder.parseConfiguration()
方法中找到。executor
我们在上面提到是创建的CachingExecutor
实例,所以代码走到该类的query
方法。
1 | public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) |
我们可以看到,代码先去查找MappedStatement
对应的缓存,如果找不到缓存会委派到具体的具体的类去查询,可以进入BaseExecutor
的query方法,首先他也会查询缓存,这个缓存是SqlSession
的本地缓存,如果没有缓存才会从数据库去查找。
至此,一个sql的执行的主流程就到此结束了。