搜索
您的当前位置:首页正文

Mybatis源码Debug追踪

来源:榕意旅游网

在学习JavaWeb开发时少不了要和数据库打交道,记得最初是学习JDBC,每次都需要手动加载Driver、配置数据库连接信息、创建连接、执行Sql等操作,是一种硬编码方式,很不方便。于是为了偷懒,接触了Mybatis框架,用起来真的很爽,尤其是在Springboot中,由于`MybatisAutoConfiguration`的存在,我们只需要简单的做一些连接信息的配置,就可以只关注Sql本身和Dao层接口就好了。用了这么久,只知道Mybatis是替代人来做那些重复性的工作,但是并没有深入去探索怎么实现的,怀着好奇心,今天debug一下源码,深入认识一下它。

1、Mybatis初始化追踪

1、`MybatisAutoConfiguration.class`

在`MybatisAutoConfiguration`的`sqlSessionFactory`方法打上断点,发现`dataSource`参数里面已经包含了我们在`application.properties`中配置的数据库相关信息,说明在此之前,配置文件已经被加载好了,于是,我们看一下在`MybatisAutoConfiguration`这个类之前,Springboot做了哪些事情。

这就很清晰了,在此之前,Springboot框架已经对数据源进行了自动配置。

通过`sqlSessionFactory`方法中对`SqlSessionFactoryBean`实例进行一系列的配置后,最后返回了该实例中的数据。

看一下`getObject()`中返回了啥

2、SqlSessionFactoryBean.class

我们发现,`SqlSessionFactoryBean`中的`sqlSessionFactory`对象此时还是null,那么可以判断afterPropertiesSet()方法中一定是根据刚才的配置去初始化`sqlSessionFactory`对象,点进去一探究竟。

果不其然,在这里我们才看到真正初始化`sqlSessionFactory`对象的操作。

从注释中可以了解到`buildSqlSessionFactory()`方法可以根据XML配置信息或者`Configuration`实例创建了一个`SqlSessionFactory`实例,如上文所述,配置信息已经自动加载进来了,所以这里直接根据`Configuration`实例创建`SqlSessionFactory`。

里面涉及包扫描、mapper.xml等配置信息处理。

3、`SqlSessionFactoryBuilder.class`

最终将处理好的配置信息传给`SqlSessionFactoryBuilder`的`build`方法

至此呢,SqlSessionFactory实例就算是创建完成了。

2、debug查询接口链路

首先是进入了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实例的关闭。

3、总结

  • Mybatis框架帮助开发者从底层的JDBC操作中解放出来,以面向对象的方式进行持久化操作,只需要关注操作的SQL语句即可。而底层数据库连接的获取、数据访问、事务等实现都不需要关心,从而将应用层从JDBC抽取出来。
  • `SqlSessionFactory`、`SqlSession`是Mybatis的核心类,SqlSessionFactory可以通过SqlSessionFactoryBuilder获取,SqlSessionFactoryBuilder主要是通过XML配置或者初始化好的Configuration实例来创建`SqlSessionFactory`对象。`SqlSessionFactory`是线程安全的,它是创建SqlSession的工厂。
  • SqlSession是独立的,即每一个SQL操作对应一个SqlSession,它是应用程序与持久层之间交互操作的一个单线程对象,所有的SQL操作都有它来完成,它底层封装了JDBC连接。SqlSession不可被多个操作共享,非线程安全。每次执行完成后,当前的SqlSession实例都会在finally块中保证其关闭。
  • 每个SqlSession底层都会通过`SpringManagedTransaction`创建Connection,即和DB建立通信连接,这是十分消耗资源的,而往往在进行执行了SQL语句后就要抛弃掉该Connection实例,这是很大的浪费,因此推荐使用PooledDataSource,减少资源浪费。

4、附录

1、SqlSession接口

2、SqlSessionFactory接口

3、SqlSessionFactoryBuilder接口

因篇幅问题不能全部显示,请点此查看更多更全内容

Top