Fork me on GitHub

MyBatis源码解析【6】SqlSession运行

前言

这个分类比较连续,如果这里看不懂,或者第一次看,请回顾之前的博客

http://www.cnblogs.com/linkstar/category/1027239.html

经过之前的学习我们知道了工厂是如何建立的,是如何生产产品的。

那么今天要进入重点中的重点了。那就是我们究竟是如何使用这个产品的。

也就是SqlSeesion究竟是如何运行的,内部究竟有些什么东西。

这部分很难,需要使用到我们之前的基础装备哦。

 

产品运行的大致步骤

我们还是老规矩从外部来看看是如何运行的。

SqlSession session = sqlSessionFactory.openSession();Demo demo = (Demo) session.selectOne("com.xex.dao.mapper.DemoMapper.selectDemo");session.close();从外部看,最简单的情况就是这样,看起来比较简单。1、从工厂获取产品(获取产品已经在上节提到,这里就不多说了)2、执行需要的sql方法(重点)3、关闭产品(回收产品) 

产品运行的内部过程

从大致的步骤我们可以看出重点就在第二步上面了。怎么随便调用一个方法就能执行sql了呢?过程复杂,我尽量讲的仔细一些。我们就以这个查询来作为例子。 首先我们进入selectOne方法里面看看。(idea使用快捷键Ctrl+Alt+B查看光标上的方法的实现)

image

我们需要查看的是DefaultSqlSession的实现,至于为什么之前已经讲过咯。

image

留意一个地方,我们传入的参数statement="com.xex.dao.mapper.DemoMapper.selectDemo"

image

从大方向上看,传入的参数是“com.xex.dao.mapper.DemoMapper.selectDemo”,返回的参数是一个类MappedStatement

image

 

mappedStatements简述

这里用文字来叙述一下这个mappedStatements的构建思路。因为具体细节太多,就不一一截图说明了,就截图重点部分了,希望你能跟上并按照思路去源码中寻找。

但是这个类里面一些细节值得我们学习和研究,所以很值得看看。

1、首先这mappedStatements是我们熟悉的Configuration类中的一个变量。

2、是这样被new出来的:new StrictMap

3、StrictMap是Configuration中的一个内部类继承自HashMap,与之不同的是的,这个map有个名字name的变量,然后主要不同在于这个map的put和get方法。

4、put方法中:

image

下面有这么几句话是用来描述这个put方法的,看完之后仔细思考,这三条是怎么总结出来的。

一、这个map会把com.xex.dao.mapper.DemoMapper.selectDemo这种包名按照“.”拆分后取出最后一个元素,这里就是selectDemo。(只是举例)

二、这个map的值都是String,如果在put的时候发现有相同的key,那么不会马上抛出异常,而是覆盖了重复的键,把重复键的值修改成了Ambiguity类型。

三、Ambiguity这个类其实就是一个字符串。

首先对于第一条,因为拆分之后最后的selectDemo是我们写的一条条sql语句的id,mybatis是通过这个id去寻找需要运行那一条数据库语句的,所以这个必须唯一。而存放的时候只需要最后的selectDemo就可以了。

那么就奇怪了,为什么mybatis遇到相同的键也就是有两条sql语句有相同的id时没有直接选择在加载配置的时候就抛出异常而是存放了一个奇怪的Ambiguity类型呢?(Ambiguity的意思是含糊的,不明确的)

让我们来看看get方法应该就明白了。

image

一、调用父类的get也就是HashMap的get方法。

二、空值抛异常

三、Ambiguity抛异常

聪明的你应该已经明白了。

给笨笨的你解释一下,空值抛异常就是通过这个id找不到对应的需要执行的sql语句当然就异常了;当Ambiguity抛异常就表面有两个id相同的sql语句,mybatis不知道要执行哪一个了,所以异常了。

剩下的就是这个map是什么时候建立的呢?当然是一开始建造工厂的时候咯,之前有讲过,不明白可以翻翻前面的,复习一下咯。

具体在MappedStatement里面sql是怎么存放的,有兴趣的可以直接进这个类看看。这里我们就讲到这里了,要继续主进程了。

 

sql的执行

我们继续来接着之前的来看,获得了sql之后怎么执行的呢?

return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

首先是谁去执行的?一个叫做executor的东西。

我们叫它执行者。它是一个接口。然后在产品生产的时候就被赋值了。

然后是它去执行的query方法,返回值是一个泛型约束的List。

 

然后我们来看参数:

1、ms是我们刚才获得的执行语句。

2、wrapCollection是将当前的参数,也就是数据库查询的时候的入参,比如查询条件,如果查询条件是集合(Collection)或者数组(Array)形式的话转换成map,如果不是就直接返回。

我们现在没有入参,所以返回的是个null

3、rowBounds   mybatis的分页功能,我们不管他

4、Executor.NO_RESULT_HANDLER

是个null,叫做没有结果的处理器

 

然后我们来看看执行

image

image

 

下面就是关键了!!!注意咯

image

从缓存中拿我们就不看了,比较简单,缓存其实是个map嘛

我们就看从数据库查询

image

 

image

下面走这个

image

image

看到这里的excute没有,这里就是真正的执行sql了,里面呢就是传说中的jdbc了,喜欢你就进去看看,不喜欢我们继续看看结果集最后是如何映射的。

 

对返回结果的处理

image

 

 

至此整个sql在mybatis中的执行过程终于是完成了。

整条路线如果仔细来看真的很长,不得不佩服设计者如此缜密的设计。

 

总结

我们经过整个路线的行走,我们已经明确了sql在mybatis中执行的全部过程。

相信你也有所收获,其实我们应该多想想设计者为何这样设计,有的代码为什么要这样写。这样写的好处和设计思路又是什么。有什么样的优化或者优点值得我们学习。

不过不要高兴的太早。

这还没完呢!

我们的装备到现在还没用上呢!后面一篇就会讲解,为什么只需要定义一个接口在mybatis中就能起作用,不需要实现类。

代理模式在其中的运用以及反射的强大。

希望上面的思路对你看源码有帮助。如有问题还请多多提出,不胜感激。

转载请注明出处:http://www.cnblogs.com/linkstar/category/1027239.html

作者:LinkinStar

 

posted @ 2017-07-15 14:50  LinkinStar  阅读(1376)  评论(0编辑  收藏  举报