这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战
我们在之前为了方便写了一获取SqlSession的工具类,我们今天来分析一下Mybatis的执行流程
1 | ini复制代码String resource = "mybatsi-config.xml"; |
这是我们根据id查询学生信息的代码,通过代码我们发现Myabtis的执行流程是
- 获取Mybatis主配置文件
- 通过SqlSessionFactoryBuilder().build()方法传入主配置文件构建SqlSessionFactory对象
- SqlSessionFactory对象通过openSession()获取SqlSession对象
- sqlSession.getMapper()方法获取我们xml文件得到mapper对象去执行我们的sql返回对象
到底具体怎么只执行,我们来看源码看都做了些什么
Mybatis的组件
SqlSessionFactoryBuilder
通过SqlSessionFactoryBuilder这个建造者通过XMLConfigBuilder()读取传入的inputStream的Mybatis主配置文件的流,XMLConfigBuilder.parse()解析主配置文件返回一个Configuration()对象,在调用一个build方法返回一个SqlSessionFactory()对象,还有两个参数SqlSessionFactory和properties,environment 决定加载哪种环境,包括数据源和事务管理器,比如我们的项目有 开发环境,UAT测试环境,在配置文件中<environments中有多个environment。properties是来加载一些属性的。
上边结束后我们返回一个SqlSessionFactory()对象
1 | typescript复制代码public SqlSessionFactory build(InputStream inputStream, String SqlSessionFactory, Properties properties) { |
SqlSessionFactory
有了SqlSessionFactory之后我们就可以tong过他来获取SqlSession对象,SqlSessionFactory重载的多个 openSession() 方法供使用,通过参数命名我们可以知道下边的方法参数是做什么的,我们默认的openSession()方法是没有参数的,会创建包含如下属性的SqlSession对象
autoCommit
是否自动提交Connection
创建数据库会话TransactionIsolationLevel
事务隔离级别ExecutorType
执行器类型
ExecutorType有三种类型
SIMPLE
该类型的执行器没有特别的行为。它为每个语句的执行创建一个新的预处理语句REUSE
复用预处理语句BATCH
该类型的执行器会批量执行所有更新语句
1 | csharp复制代码public enum ExecutorType { |
还有一个getConfiguration方法,获取Configuration对象,也就是解析xml配置文件中的<configuration标签后的数据
1 | scss复制代码public interface SqlSessionFactory { |
看我啊接口我们再去看SqlSessionFactory的实现类 DefaultSqlSessionFactory()每一个openSession方法都要调用openSessionFromDataSource去返回SqlSession对象
- 先获取我们主配置文件的environment包函数据库配置和事务信息,
- 创建TransactionFactory事务工厂,调用newTransaction方法传入,数据库信息,隔离级别,是否自动提交。
- 新建一个构造器executor传入事务,构造器类型
- 返回一个 DefaultSqlSession对象
这是我们就获得一个SqlSession对象,我们的sql语句都是executor在帮我们执行,excutor是对于Statement的封装
1 | ini复制代码private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { |
SqlSession
SqlSession是Mybatis最强大的一个类,通过DefaultSqlSession的getMapper()来生成mapper的代理对象
SqlSessionManager.java
1 | typescript复制代码public <T> T getMapper(Class<T> type) { |
Configuration.java
1 | typescript复制代码public <T> T getMapper(Class<T> type, SqlSession sqlSession) { |
MapperRegistry.java
1 | typescript复制代码public <T> T getMapper(Class<T> type, SqlSession sqlSession) { |
MapperProxyFactory.java 动态代理我们的接口
1 | kotlin复制代码protected T newInstance(MapperProxy<T> mapperProxy) { |
这一通操作之后我们就拿到了代理对象去执行我们的方法,走的方法是MapperProxy的invoik方法
1 | kotlin复制代码public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
调用 mapperMethod.execute(this.sqlSession, args)判断是什么类型的sql,返回给sqlSession
1 | kotlin复制代码public Object execute(SqlSession sqlSession, Object[] args) { |
我们现在看是如何实现getlist的
1 | arduino复制代码<E> List<E> selectList(String var1); |
1 | typescript复制代码public <E> List<E> selectList(String statement) { |
这里调用的.executor.query方法。可以看到有两个实现
1 | kotlin复制代码public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { |
走CachingExecutor的query方法,先从二级缓存中获取,,没有的话走走另一个方法去一级缓存中那,没有的话
1 | kotlin复制代码public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { |
没有的话走queryFromDatabase方法去数据库查数据
1 | kotlin复制代码private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { |
走doquery方法有四个实现,我们看SimpleExecutor的DoQuery方法
1 | ini复制代码public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { |
然后走StatementHandler的query方法,可以看到是statement去执行SQL语句了
1 | java复制代码public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { |
本文转载自: 掘金