代码直接引用 juejin.cn/post/684490… demo代码,由于没有经历过手动连接数据库的时代,不知道具体流程是啥,debug看吧。
此篇主要看下插入操作的大体流程,之后的篇章会做具体分析
- 首先在插入方法处打断点,开始执行
- 可以看到userMapper被代理了
- 进入insert方法
- 继续执行,走到cachedInvoker这步,进入
- 计算此method是否为缓存方法
- m 就是刚才的insert方法,我们进入isDefault方法中看下,此方法判断是否为在接口中声明的带有方法体的非抽象实例方法(这里感觉有问题,interface有方法体的方法不就是抽象方法吗,回头再研究下)
// ****************************** todo ******************************
- 上边问题还没解决,先继续
- 这里我们看到了这个方法,获取数据库配置,从这里我们可以一路回溯点击找到加载配置的起点(当然这是我看代码的流程,你如果知道mybatis怎么加载运行的可以直接从头看起)
- 经过一路漫长的点点点,我们找到了此方法,sqlSessionFactory
- 可以看到这个方法所在的类实现了InitializingBean接口
InitializingBean接口的作用:InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候,在所有的properties被注入后都会执行该方法
- 此类的 afterPropertiesSet 方法做了一些检查工作,我们可以先略过
继续看我们的主角sqlSessionFactory,通过注解可以看到此方法的执行时机是@ConditionalOnMissingBean,此方法做了一系列的设置工作,包括各种数据库连接参数,driver,language level等
进入getObject方法
- 通过afterPropertiesSet初始化SqlSessionFactory
- 进入buildSqlSessionFactory方法,可以看到此方法设置了一系列的config,targetConfiguration,用来构建一个默认的SqlSessionFactory实例,此时mybatis的配置已设置完成
初始化配置文件信息的本质就是创建Configuration对象,将解析的xml数据封装到Configuration内部的属性中。
- 9 ~ 15 是mybatis配置的加载过程,接下来我们继续从8开始,进入new MapperMethod()
- 顾名思义,通过方法名我们知道此方法是用来设置sql的
- 通过debug看到此sql的类型是INSERT
- 经过一系列设置操作后,终于该轮到执行了,进入PlainMethodInvoker方法
- 通过以下构造函数,我们得到了一个MapperMethodInvoker接口的实例PlainMethodInvoker
- 回到4
- 进入invoke方法
- 进入execute方法,可以看到这里是mybatis执行调用的地方
- 我们现在是insert方法,进入convertArgsToSqlCommandParam方法看下
- 得到的param就是我们的测试数据
- 进入insert方法
SqlSession: SqlSession中的两个最重要的参数,configuration与初始化时的相同,Executor为执行器
- SqlSession是一个接口,它有两个实现类:DefaultSqlSession(默认)和SqlSessionManager(弃用,不做介绍)
- SqlSession是MyBatis中用于和数据库交互的顶层类,通常将它与ThreadLocal绑定,一个会话使用一个SqlSession,并且在使用完毕后需要close
Executor也是一个接口,他有三个常用的实现类:
- BatchExecutor(重用语句并执行批量更新)
- ReuseExecutor(重用预处理语句prepared statements)
- SimpleExecutor(普通的执行器,默认)
- buildAllStatements方法,引用下翻译:解析缓存中所有未处理的语句节点。建议一旦添加了所有映射器,便调用此方法,因为它提供了快速失败语句验证
- 回到26我们得到一个MappedStatement
- 接下来进入update方法
- BaseExecutor.update
- SimpleExecutor.doUpdate
- SimpleExecutor.prepareStatement
- RoutingStatementHandler.prepare
- 这里可以进去看下最终需要执行的sql
RoutingStatementHandler.parameterize
PreparedStatementHandler.parameterize
- 看下prepareStatement最终得到的声明
- 回到31进入RoutingStatementHandler.update
- 进入PreparedStatementHandler.update
- HikariProxyCallableStatement.execute
- ClientPreparedStatement.execute
- ClientPreparedStatement.executeInternal, 此方法是真正执行准备好的sql的方法
- 最后SimpleExecutor.doUpdate关闭资源