深入分析mybatis工作原理
Mybatis分析
通过分析了mybatis的源码我觉得大致分为三步
1. 获取数据源:
SqlSessionFactory.build(inputStream)–>XMLConfigBuilder–>Parse–>PaseConfiguration–>build(Configuration)–>DefaultSqlSessionFactory–>DataSource
2. 获取sql
openSession()–>DefaultSqlSession–>getMapper()–>execute–>getBoundSq
3. . 执行sql(SqlSession)
SimpleExecutor–>query()–>createCacherKey–>doQuery–>newStatementHander–>prepareStatement—>instantiateStatement
mybatis执行流程
接下说一下具体流程
一、根据配置文件创建SqlSessionFactory
- 创建SqlSessionFactoryBuilder 对象 SqlSessionFactoryBuilder
- 调用build(inputStream)方法 XMLConfigBuilder
- 创建解析器 parser
- 解析每一个标签把详细信息保存在Configuration中 Configuration
- 解析mapper.xml 把mapper.xml 中的每一个元素信息解析出来并保存,在全局配置中将增删改查标签的每一个标签每一个属性都解析出来
- 返回Configuration
- bulid(Configuration)
- new DefaultSqlSession()
- 返回创建的DefaultSqlSession,包含了保存全局配置信息的Configuration
10.最终返回DefaultSQLSessionFactory
总结:Configuration 封装了所有配置文件的信息, 把配置文件的信息解析并保存在Configuration对象中,返回包含了Configuration对象的DefaultSqlSession对象
二、返回SqlSession的实现类DefaultSqlSession对象,它里面包含了Configuration和Executor(Executor会在这一步被创建
- 调用openSession方法
- openSessionFromDataSource()
- 创建一些信息,创建事务等
- newExecutor()
- 根据Executor在全局配置中的类型,创建出SimpleExecutor/ReuseExecutor/BatchExecutor 说明:Executor接口中定义了增删改查的方法
- 如果有二级缓存,就会创建CachingExecutor(executor)
- 调用interceptorChan.plugnAll(executor) 说明:使用每一个拦截器重新包装executor并返回
- 创建DefaultSqlSession,包含了Configuration和Executor
- 最终返回DefaultSqlSession
三、getMapper返回接口的代理对象(包含了SqlSession对象)
- DefaultSqlSessionFactory.sqlSession() 调用Configuration.getMapper(type),,又会从MapperRegistry调用getMapper()拿到MapperproxyFactory
- 根据接口类型获取MapperProxyFactory
- 然后newInstance(SqlSession)
- 创建MapperProxy,他是一个invocationHandler(动态代理需要的)
- 创建MapperProxy()代理对象
- 返回MapperProxy代理对象
四、执行查询
- MapperProxy----invoke()-----MapperMethod----execute(SqlSession,args)
- 判断增删改查类型
- 包装参数为一个map或者直接返回
- 调用SqlSession.selectOne() 最终调用selectList()
- 获取MappedStatement executor.query(ms,xx,x)
- 通过MappedStatement.getBoundSql()获取到绑定的sql语句
- 查看本地缓存是否有数据,没有就调用queryFromDatabase,查出后会保存到本地缓存
- doquery()
- 创建statementHandler对象,PreparedStatementHandler
- 调用interceptorChan.plugnAll(statementHandler) 说明:使用每一个拦截器重新包装executor并返回
- 创建ParameterHandler 调用interceptorChan.plugnAll(ParameterHandler)
- 创建ResultSethandler 调用interceptorChan.plugnAll(resultSethandler)
- 预编译sql,产生PreparedStatement对象
- 调用ParameterHandler来设置参数
- 调用TypeHandler来预编译设置参数
- 查出数据使用resultHandler处理结果、使用typeHandler获取value值
- 后期关闭连接等操作
- 如果只有一条数据,返回查询list的第一个
查询流程总结:
代理对象–》DefaultSqlSession–》Executor–》StatementHandler—设置参数—ParameterHandler — TypeHandler -----原生的JDBC,Statement,PreparedStatement—处理结果— ResultSethandler—
statementHandler:处理sql语句预编译,设置参数的相关工作
ParameterHandler: 设置预编译参数用的
ResultSethandler:处理查询后的结果集
TypeHandler:在整个过程中,进行数据库类型和javaBean类型的映射.
五、mybatis总结:
- 根据配置文件(全局,sql映射) 初始化出Configuration对象,
- 创建出DefaultSqlSession对象,它里面包含了Executor(根据全局配置文件中defaultExecutorType创建出对应的Executor)和Configuration
- DefaultSqlSession.getMapper(),难道对应接口的MapperProxy,
- MapperProxy里面有DefaultSqlSession
- 执行增删改查
1、调用DefaultSqlSession的增删改查
2、会创建StatementHandler对象。(同时也会创建ParameterHander和ResultSetHandler)
3、调用Statementhandler预编译参数以及参数值
使用ParamterHandler来给sql设置参数
4、调用StatementHandler的增删改查方法
5、ResultSetHandler封装接口
最后补充一点
mybaits插件原理
在四大对象创建的时候
1. 每个创建出来的对象不是直接返回的,而是interceptorCHan.pluginAll(parameterhandler);
2. 获取到所有的Interceptor(拦截器)(插件需要实现的接口),调用interceptor。披露滚(target);返回target包装后的对象
3. 插件机制,我们可以使用插件目标对象创建一个代理对象,AOP,我们的插件可以为四大对象创建代理对象,代理对象可以拦截到四大对象的每一个执行
我想大家如果把这个掌握,mybatis的执行流程才能完全掌握,如果是面试的话,挑些重要的说说感觉就没什么问题,当然,如果你大部分都能说下来,效果会更好,可能有些细节,面试官都没有注意到过。
如果这篇文章对大家有一点帮助,点个赞哈。。。。。。。。。。。。。