所有语句的执行都是通过SqlSession对象来操作的,SqlSession是由SqlSessionFactory类生成的。
首先根据配置文件来创建一个SqlSessionFactory,然后调用openSession来获取一个SqlSession。我们从时序图来看看可能会更加清晰
(1)生成SqlSessionFactory对象(默认实现是DefaultSqlSessionFactory)的过程
(2)获取SqlSession对象
通过调用DefaultSqlSessionFactory的openSession()方法来获取SqlSession对象。
通过代码可以看出,最终返回的是一个DefaultSqlSession实例对象。接下来就是根据这个DefaultSqlSession来获取对应的Mapper对象。
(3)获取MapperProxy对象
MapperRegistry类中:
MapperProxyFactory类中:
从代码可以看出来,其实我们调用sqlSession.getMapper(UserDao.class)方法的时候,返回的是一个和UserDao接口对应的MapperProxy代理对象。如下定义所示,MapperProxy类是一个实现了InvocationHandler的代理类:
(4)Executor对象
当拿到了UserDao对象(其实是MapperProxy代理对象)后,我们调用Dao接口中定义的方法,如下所示:
这时候便调用了MapperProxy对象的invoke方法了;
MapperMethod类中:
从上面这个方法实现上可以看出,已经根据执行方法(CRUD)进行了不同的处理,我们简单看一个方法executeForMany,代码如下所示:
通过观察这些代码,发现最终的实现都是通过sqlSession对象来进行操作的。我们继续往里看,看看selectList方法:
可以看到,内部是把查询操作委托给了一个Executor对象(即executor.query()),Executor是一个接口,mybatis为其实现了一个抽象基类BaseExecutor,我们跟踪上面的代码中的query方法继续往里看:
BaseExecutor类中:
在上面的方法中,我们看到当list==null的时候会调用queryFromDatabase()方法,这个方法如下:
然后会调用doQuery()方法,BaseExecutor中的doQuery方法定义成了抽象方法,由具体的继承类进行个性化的实现。这里,我们拿mybatis中默认使用的SimpleExecutor来看看:
SimpleExecutor类中:
从这个方法可以看到,首先根据调用Configuration类的newStatementHandler方法来获取一个sql操作对象:
Configuration类中:
RoutingStatementHandler类中:
可以看到,这里根据配置来创建Statement、PreparedStatement或者CallableStatement三者之中的一个。然后调用相应的方法,如query()方法。以SimpleStatementHandler为例,我们看看具体的sql操作:
看到这里,我们终于看到了黎明的曙光,因为这里已经看到Jdbc中的数据库操作代码了,即statement.execute(sql)。在查询完之后使用resultSetHandler来进行查询结果集的处理。
上面的代码的整体流程图大概如下所示: