MyBatis学习及SpringBoot对MyBatis的封装
以前只是简单的用了一下MyBatis,对于内部是如何工作的并不清楚
以下是从各个网站找到的MyBatis的原理
启动/初始化:
SqlSessionFactory(接口):创建的是DefaultSqlSessionFactory,会完成全局配置文件和映射文件的加载解析操作,把配置相关的信息保存在factory的Configuration中
处理请求:
通过SqlSessionFactory获取SqlSession对象,创建的是DefaultSqlSession
SqlSession提供了select、update、delete、save等方法,通过这些API(参数是sql的接口名)来操作数据库
调用对应的Executor进行处理,有配置缓存的话,先走二级缓存,没有命中再走一级缓存,再没有命中就操作数据库,交给StatementHandler来处理
通过ParameterHandler处理SQL的占位符
通过ResultSetHandler处理结果的映射
最后关闭session
实践一下,基于SpringBoot2.7 + mybatis-spring-boot-starter 2.3.2
上来就有问题了,我不需要配置mybatis-config.xml就能工作,想着应该是spring的约定优于配置,可能是有默认的配置吧
于是网上一搜,说是SpringBoot的话整合到了MybatisProperties里了,默认可以不配置
比如我要清空一级缓存的话就在properties里配置
mybatis.configuration.local-cache-scope=STATEMENT
根据上述所说,我来看看我的这个配置有没有生效
接下来按上面说的就是处理请求的时候会创建session
写个controller,调用一下这个接口,怎么回事,debug发现我的请求进来,sqlSession都是同一个呢,根本没有所谓的openSession和closeSession,而且这个变量是个final,难道上面说法不对
不过这个SqlSession不是上面说的DefaultSqlSession,而是SqlSessionTemplate
对比这两家伙,都是实现了SqlSession,但是package不一样,一个是mybatis原生的,一个是spring的,都不是同一个mother
看样子可能SqlSessionTemplate是mybatis为了SpringBoot又加的一些东西,而且这个SqlSession都不支持手动的commit,rollback
看看源码里是怎么注释的,大概就是说,SqlSessionTemplate是线程安全的,单例的,和Spring事务能够兼容,而且完全由Spring事务来管理session的生命周期。
那如果没有Spring事务呢,我们后面再来解释
再从service层调用开始debug
首先,MyBatis (Spring)启动的时候,使用JDK动态代理,把单例的SqlSessionTemplate作为参数来实例化各个mapper,
然后调用mapper的方法时,就会进入到MapperProxy的invoke方法,然后执行MapperMethod的execute方法,根据sql的类型(增删改查)调用sqlsession不同的API
进入到SqlSessionTemplate,怎么还有动态代理,以前我大概知道会对mapper的接口进行动态代理,没想到SqlSession里面还有,盲猜可能是为了处理事务相关的东西,commit,rollback相关的东西,毕竟SqlSessionTemplate不支持手动调用rollback,commit等
此处是代理了DefaultSqlSession,原来是在这里去获取了真正的sqlSession,调用sqlSession
此处通过动态代理去反射调用sqlSession的API,然后调用Executor去执行sql语句,包括执行前sql语句处理参数,执行完对结果集的处理和映射,因为此处的service方法上我加了@Transaction注解,所以上图197行的commit是不会去执行的,具体的commit是交由Spring 事务管理来控制。
所以网上说的还是没错,只不过Spring帮我们做了session的创建,commit和rollback,并且根据Spring的事务来决定此次sql语句是否commit,这就回答了上面,
如果没有Spring事务 =》 那就直接commit
如果有Spring事务,sqlSession会尝试从SqlSessionHolder里面拿,拿不到(说明这是此次事务里的第一个sqlSession)就新open一个session,然后执行完sql语句后并不去commit,而是最后在Transaction提交事务的时候,调用sqlSession的commit。
总结:
网上说的不错,是mybatis的核心处理过程,而我们日常使用的是SpringBoot+MyBatis,Spring帮我们做了很多东西,包括open session、commit、rollback和close,并且是和Spring的事务绑定在一起。