在学习JavaWeb开发时少不了要和数据库打交道,记得最初是学习JDBC,每次都需要手动加载Driver、配置数据库连接信息、创建连接、执行Sql等操作,是一种硬编码方式,很不方便。于是为了偷懒,接触了Mybatis框架,用起来真的很爽,尤其是在Springboot中,由于`MybatisAutoConfiguration`的存在,我们只需要简单的做一些连接信息的配置,就可以只关注Sql本身和Dao层接口就好了。用了这么久,只知道Mybatis是替代人来做那些重复性的工作,但是并没有深入去探索怎么实现的,怀着好奇心,今天debug一下源码,深入认识一下它。
在`MybatisAutoConfiguration`的`sqlSessionFactory`方法打上断点,发现`dataSource`参数里面已经包含了我们在`application.properties`中配置的数据库相关信息,说明在此之前,配置文件已经被加载好了,于是,我们看一下在`MybatisAutoConfiguration`这个类之前,Springboot做了哪些事情。
这就很清晰了,在此之前,Springboot框架已经对数据源进行了自动配置。
通过`sqlSessionFactory`方法中对`SqlSessionFactoryBean`实例进行一系列的配置后,最后返回了该实例中的数据。
看一下`getObject()`中返回了啥
我们发现,`SqlSessionFactoryBean`中的`sqlSessionFactory`对象此时还是null,那么可以判断afterPropertiesSet()方法中一定是根据刚才的配置去初始化`sqlSessionFactory`对象,点进去一探究竟。
果不其然,在这里我们才看到真正初始化`sqlSessionFactory`对象的操作。
从注释中可以了解到`buildSqlSessionFactory()`方法可以根据XML配置信息或者`Configuration`实例创建了一个`SqlSessionFactory`实例,如上文所述,配置信息已经自动加载进来了,所以这里直接根据`Configuration`实例创建`SqlSessionFactory`。
里面涉及包扫描、mapper.xml等配置信息处理。
最终将处理好的配置信息传给`SqlSessionFactoryBuilder`的`build`方法
至此呢,SqlSessionFactory实例就算是创建完成了。
首先是进入了MapperProxy.class,显然是采用了动态代理模式来实现我们在UserDao接口中定义的方法来完成查询逻辑。
可以看到mybatis是加了缓存逻辑的
从缓存中拿到invoker后执行`invoke()`方法
在这里我们可以清晰看到当前接口以及输入参数的细节信息,入当前接口的入参为`id`。
接下来执行`execute`方法。
来到SELECT类型的逻辑。
Mybatis会根据当前接口返回的种类来判断具体执行哪种执行逻辑,因为这会涉及到结果集映射。在这里是返回单个User实例对象,于是在转换参数后调用sqlSession的selectOne方法。
这里同样用到了动态代理模式来获取sqlSession。
在` getSqlSession()`方法中,我们可以看到,最终通过sqlSessionFactory的openSession方法来创建sqlSession实例对象。
至此,sqlSession创建完成,回到invoke方法中,
代理执行selectOne方法
在真实执行逻辑中,通过Dao层的接口全限定名拿到xml中对应的sql标签,获取sql详细信息,然后去与DB进行交互,执行查询逻辑。
在执行query方法中,首先拿到与Dao接口绑定的Sql语句,然后根据MappedStatement、参数、行数和绑定的sql来创建缓存Key
因为当前还没有缓存,所以执行正常的查询逻辑。
即真实的从DB中去查询数据。
在与DB交互前,先进行缓存。
接下来就看到了JDBC中熟悉的PrepareStatement。
获取连接
实际上是交由`SpringManagedTransaction`实例来创建与DB的连接的
在`SpringManagedTransaction`中根据之前配置好的数据源信息去创建与DB的连接。
至此,Statement实例初始化完成
然后用Statement去执行Sql查询
并对查询结果转换为我们需要的User实例。
完成查询结果转换,返回User实例。
拿到查询结果后,因为我们查询业务是没有加入事务的,所以查询的结果会直接返回。
最终,在finally块中保证sqlSession实例的关闭。
因篇幅问题不能全部显示,请点此查看更多更全内容