MyBatis源码之MyBatis中SQL语句执行过程

MyBatis源码之MyBatis中SQL语句执行过程

SQL执行入口

我们在使用MyBatis编程时有两种方式:

方式一代码如下:

SqlSession sqlSession = sqlSessionFactory.openSession(); List<Student> studentList = sqlSession.selectList("com.sjdwz.dao.StudentMapper.findAll"); 

方式二代码如下:

SqlSession sqlSession = sqlSessionFactory.openSession(); StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class); List<Student> studentList = studentMapper.findAll(); 

方式一入口分析

方式一调用的是SqlSession接口的selectList方法:

MyBatis源码之MyBatis中SQL语句执行过程

执行的是DefaultSqlSession中的实现

MyBatis源码之MyBatis中SQL语句执行过程

经过多次重载后,调用的是此方法:

MyBatis源码之MyBatis中SQL语句执行过程

MappedStatement封装的是我们的SQL语句;

方法内部执行的是executor的query方法。

方法二入口分析

方法二调用的是SqlSession接口的getMapper(Class type)方法:

MyBatis源码之MyBatis中SQL语句执行过程

我们实际调用的是DefaultSqlSession实现类中的方法:

MyBatis源码之MyBatis中SQL语句执行过程

MyBatis源码之MyBatis中SQL语句执行过程

此方法内部又调用了

 configuration.<T>getMapper(type, this); 

MyBatis源码之MyBatis中SQL语句执行过程

最后调用了:

MyBatis源码之MyBatis中SQL语句执行过程

return mapperProxyFactory.newInstance(sqlSession); 

通过工厂创建了接口的代理对象。

Mapper接口动态代理

上面讲到会通过

 mapperProxyFactory.newInstance(sqlSession); 

来创建动态代理类;

那创建动态代理类会执行哪些方法呢?

MyBatis源码之MyBatis中SQL语句执行过程

可以看到有MapperProxy这个类,实际上都会执行MapperProxy类中的invoke方法。

MyBatis源码之MyBatis中SQL语句执行过程

invoke方法会先判断方法是不是Object的方法,如果是,就直接调用;否则会执行cachedInvoker()方法

cachedInvoker()的作用是获取缓存中MapperMethodInvoker,如果没有则创建一个,而MapperMethodInvoker内部封装了MethodHandler。

MyBatis源码之MyBatis中SQL语句执行过程

当cacheInvoker返回了PalinMethodInvoker实例之后,紧接着调用了这个实例的PlainMethodInvoker#invoke方法

MyBatis源码之MyBatis中SQL语句执行过程

然后就调用了execute()方法

MyBatis源码之MyBatis中SQL语句执行过程

里面调用了sqlSession的方法。

方法的调用关系如下:

MapperProxy#invoke()//代理对象执行的方法,代理后所有Mapper的方法调用时,都会调用这个invoke方法 	MapperProxy#cachedInvoker()//代理对象里的Method也是对象,为了避免频繁new对象,在这里给Method对象加缓存 		methodCache#computeIfAbsent()//从缓存中取Method对象,取不到创建之后加入缓存         //PainMethodInvoker是MapperProxy的内部类         PlainMethodInvoker#invoke()//执行方法,所有代理对象的方法都会执行同一个。代理对象本质是方法的拦截器! 			MapperMethod#execute()//执行方法,最终还是在调用SqlSession接口                 SqlSession#insert()                 SqlSession#update()                 SqlSession#delete()                 SqlSession#selectOne()                 SqlSession#selectList() 

SQL执行流程

查询SQL执行流程

主要步骤:

  1. selectOne/selectList
  2. SQL获取
  3. 参数设置
  4. SQL执行
  5. 封装结果集

调用关系如下:

DefaultSqlSession#selectOne()//执行单记录 DefaultSqlSession#selectList()//查询列表     CachingExecutor#query() 		MappedStatement#getBoundSql()//获取SQL语句 	CachingExecutor#query()//二级缓存查询 		CachingExecutor.delegate = SimplyExecutor//装饰设计模式:Caching的对SimpleExecutor查询加二级缓存装饰 	SimplyExecutor#query()     	BaseExecutor#query()//子类执行查询直接调用父类方法,一级缓存         BaseExecutor#queryFromDatabase()//缓存没有则去查询数据库,一级缓存 	SimplyExecutor#doQuery()//simple执行查询 		SimplyExecutor#prepareStatement()//准备查询语句 			RoutingStatementHandler#parameterize()//路由delegate=PreparedStatementHandler 				PreparedStatementHandler#parameterize()//设置查询参数 				DefaultParameterHandler#setParameters()//设置查询参数 			RoutingStatementHandler#query()//路由delegate=PreparedStatementHandler 				PreparedStatementHandler#query()//执行SQL,封装结果集     				PreparedStatement#execute()//执行SQL查询操作 					DefaultResultSetHandler#handleResultSets()//封装返回值,将查询结果封装成Object对象 

增删改SQL执行流程

主要步骤

  1. insert|update|delete方法分析
  2. SQL获取
  3. 参数设置
  4. SQL执行
  5. 封装结果集

MyBatis中增删改的代码如下:

//DefaultSqlSession @Override public int insert(...) { return update(statement, parameter); } @Override public int update(String statement) { return update(statement, null); } @Override public int delete(...) { return update(....); } 

我们发现,增删改最后执行的都是update,这是因为insert、update、delete实际上都是对数据库中数据的改变

执行流程为:

DefaultSqlSession#update() 	CachingExecutor#update()//执行更新 		flushCacheIfRequired()//执行增删改前,清除对应二级缓存 		CachingExecutor.delegate = SimplyExecutor//装饰模式 	SimplyExecutor#update()//调用父类模板方法 		BaseExecutor#update()//执行更新 			BaseExecutor#clearLocalCache()//清除一级缓存,LocalCache 		    BaseExecutor#doUpdate()//调用子类方法 	SimplyExecutor#doUpdate()//simple执行更新 		SimplyExecutor#prepareStatement()//准备查询语句 			RoutingStatementHandler#parameterize()//delegate=PreparedStatementHandler 				PreparedStatementHandler#parameterize()//设置查询参数 				DefaultParameterHandler#setParameters()//设置查询参数             RoutingStatementHandler#update()//delegate=PreparedStatementHandler                 PreparedStatementHandler#update()                     PreparedStatement#execute()//执行SQL,完成增删改查操作                     reparedStatement#getUpdateCount()//获取影响行数 

图示

最后我们画出执行的流程图如下:

MyBatis源码之MyBatis中SQL语句执行过程

发表评论

评论已关闭。

相关文章