前面我介绍了SqlSessionFactory和SqlSession的创建,感兴趣的童鞋可以看看我写的这两篇博客:
mybatis源码阅读之SqlSessionFactory创建
Mybatis源码阅读之SqlSession创建
最近接着在看Mybatis的源码,想知道Mybatis是如何对数据库进行操作的(最底层当然还是回归JDBC),这里做个学习笔记,也想跟大家分享下:
执行代码如图1:
通过sqlSession.selectList(“xxxx”)来一步步跟踪Mybatis是如何完成对数据库的操作的。之前的文章有说到,SqlSession是个接口,创建的时候使用的是DefaultSqlSession。图2是自己断点SqlSession获得的信息:
我在mybatis-config.xml中的配置如图3:我选择的TransactionManager类型是JDBC,数据源是PooledDataSource。这也就解释了图2中的executor的Transaction为什么是JdbcTransaction,JdbcTransaction的数据源为什么是PooledDataSource。
我之前的文章已经说明了JdbcTransactionFactory和PooledDataSource是如何创建的。
new SqlSessionFactoryBuilder().build(InputStream)
–> XMLConfigBuilder.parse()
–>XMLConfigBuilder.parseConfiguration(XNode root)
mybatis是如何获取到配置文件的用户名和密码,然后连接获取数据库连接的呢?我们来看一下XMLConfigBuilder.transactionManagerElement(XNode context)和XMLConfigBuilder.dataSourceElement(XNode context)
看看DataSourceFactory的Properties props = context.getChildrenAsProperties();做了哪些操作
XNode.getChildren()中有一句children.add(new XNode(xpathParser,node,variables)),这里的variables是一个Properties,这个variables值的初始化是通过解析mybatis-config.xml的properties标签得到的。如下图,先加载properties标签下的property,再加载properties文件中的属性,最后,判断原来是否存在一些属性,是的话就两个合并返回,否则直接返回。
再来看看DataSourceFactory的factory.setProperties(props);做了哪些操作
进行赋值前:
再回去看图2,session.selectList(“xxx”)实际上调用的是DefaultSqlSession.selectList(“xxx”);这里的executor的实现类是CachingExecutor。
调用的CachingExecutor.selectList()方法如图12,先查看缓存中是否有值,有的话从缓存中获取,没有的话查询数据库。这里的delegate属性调用的是SimpleExecutor,SimpleExecutor继承了抽象类BaseExecutor。
调用父类BaseExecutor.query()方法如图13,
调用父类BaseExecutor.queryFromDatabase()方法如图14,BaseExecutor是个抽象类,doQuery()调用的是实现类SimpleExecutor的方法。
调用子类SimpleExecutor.doQuery()方法如图15,
调用子类SimpleExecutor.prepareStatement()方法如图16,
调用父类BaseExecutor.getConnection()方法如图17,从图2中可以看到transaction的实现类是JdbcTransaction。
在创建SqlSession的时候调用了DefaultSqlSession类的openSessionFromDataSource()方法,而transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit)调用了JdbcTransactionFactory的方法来创建JdbcTransaction。见图18和图19。
调用的数据源是在mybatis-config.xml配置的PooledDataSource。
PooledDataSourceFactory的创建图6说明了。PooledDataSourceFactory继承了UnpooledDataSourceFactory,PooledDataSourceFactory的无参构造函数初始化了属性dataSource的值为PooledDataSource,而PooledDataSource的无参构造函数初始化了属性dataSource的值是UnPooledDataSource。见图19和图20。加载顺序是:PooledDataSourceFactory.dataSource–>PooledDataSource.dataSource–>unPooledDataSource.dataSource。
PooledDataSource的getConnection()方法,调用UnpooledDataSource的用户名和密码连接数据库。