获取XxxMapper对象

执行增删改查 ,调用queryStudentById(1)
如上图可以看到进入到一个invoke()方法中 invoke()方法在MapperProxy类里,该类实现了InvocationHandler接口

MapperProxy/invoke()➜InvocationHandler : JDK动态代理接口
用到了动态代理模式:增删改查➜代理对象(MapperProxy对象)-➜代理对象帮我们“代理执行”增删改查➜
XxxMapper代理对象实际就是MapperProxy对象

mapperMethod.execute(sqlSession, args):实际调用增删改查的方法,依靠了sqlSession中的configuration和 executor. .还有调用queryStudentById(23)传递的参数args,
先来看MapperMethod对象:
cacheMapperMethod(method);方法:从缓存中拿数据:methodCache.get(method),如果缓存没有再去库里面那,让后put到缓存中:methodCache.put(method,mapperMethod)

再看mapperMethod调用的execute()方法,传了当前的sqlSession对象和参数args=23


execute()方法先处理处理增删改查方法的参数args,赋值给param,再处理sqlSession
看如何处理args:method.convertArgsToSqLCommandParam(args)处理参数,我的queryStudentById(23),给的参数是23, 参数给了该方法
进入convertArgstoSqlCommandParam()方法

看到该方法返回的是paramNameResolver类的方法getNamedParams(),所以真正执行参数的是getNamedParams()方法

如果参敷是0个,reutrun null ;如果参数是1个,返回第一个 ﹔如果有多个放到Map中
我的queryStudentById(23)方法参数是1 个所以返回第一个firstKey()

参数搞定了,下一步就是执行SqlSession.selectOne()方法


刚刚convertArgsToSqlCommandParam(args)方法处理了的形参args,现在来处理另一个形参:sqlSession
sqlSession调用selectOne()方法去执行,根据我上一篇的分析,我们知道sqlSession对象中保存了configuration和执行器executor.
selectOne()很好理解,就是查询一个,queryStudentById(23)根据id来查,所以只能查到一个
进入selecOne()方法,
如下图,可以看到selectOne(statement,parameter)又调用了selectList()方法:看蓝色背景的注解:该selsectList()方法的形参statement的值为“com.lyx.mybatis.dao.StudentMapper.queryStudentById”,形参parameter:23。

继续进入selectLIst()方法,看看selectList()方法

如上图,configuration.getMappedStatement(statement)方法获取了一个MappedStatement ms,即获取到了一个增删改查的对象
【下面可以关注一下该ms对象一直在被传递,看看真正使用ms对象的是哪个方法】
来看下一步,executor.query( ms,this.wrapCollection(parameter),.....)该方法套方法,所以先执行wrapCollection( )方法,先进入该方法,如下:我的参数是23不是collection类型,所以返回了object=23;


出来以后,继续执行进入selectList()方法中的executor.query(ms,param,....)方法

看到一个query()方法调用了getBoundSql()方法,进入getBoundSql()方法看看如何执行

得出结论:
boundSql:是将我们写的 SQL 和 参数值 进行了拼接后 的对象,即最终能被真正执行的SQL。
下面回到query()方法进行执行,下面执行createCacheKey(ms,param,.....)方法,createCacheKey()支持不同级别的缓存,默认是二级缓存

继续执行

当前query()方法是selectList()方法里面的executor.query()里面又一个query()方法,该query(ms,param,....)方法返回值如下


ctrl键,发现delegate是Executor类型,
再次进入
selectList()方法里面的executor.query()里面又一个query()方法的delegate.query(ms,param,....)方法

可以看到调用了queryFromDatabase(ms,param,.....)方法,中文翻译过来就是从数据库里面查
如果缓存中没有要查询的内容,则进入数据库 ,真实查询的是queryFromDatabase() 方法
进入queryFromDatabase()方法,看看如何从数据库查数据


进入
selectList()方法里面的executor.query()里面又一个query()方法的delegate.query()方法
的queryFromDatabse()方法中的doQuery()方法

ms被调用:ms.getConfiguration()获取了Configuration对象:保存了所有的配置信息;
ms.getStatementLog()获取一个Log对象
StatementHandler对象:我们进入newStatementHandler方法中看看如何执行的:


【重点】如上图:interceptorChain.pluginAll()方法拦截statementHandler,把statementHandler对象拦截,并增强,然后返回一个更强大的statementHandler
,我们再看prepareStatement()方法:


this.getConnection(statementLog)获取了数据库连接
handler.prepare()方法第一个形参为连接conn,第二个是事务的超时时间
最后执行handler.parameterize(Statement statement);进入parameterize方法

【重点】如下图,进入parameterize()方法后,执行下去,dalegate:PreparedStatementHandler

进入delegate.parameterize()方法可以看到如下图,该parameterize方法经statement对象强转为PreparedStatement
可以得出结论:mybatis的底层使用的jdbc对象的PreparedStatement

prepareStatement执行完以后,
跳出来回到doQuery()方法,接下来执行handler.query()

进入handler.query()方法
上面query()方法可以得出结论:mybatis底层执行增删改查是通过PreparedStatement的execute()方法
【重点】如下图:handler.query()方法返回DefaultResultSetHandler

到此为止selectList()方法执行完毕,下一步return list.get(0)返回list集合的第一个元素

上面有StatementHandler➜ParameterHandler➜ResultSetHandler
以上处理器分别是处理对象的处理器:StatementHanler
处理参数的:ParameterHandler
处理结果集的:ResultSetHandler
还要一个类型转换的TypeHanlder)(例如把类的boolean类型属性转为int类型存入数据库)

回到:


mapper对象包含:
- sqlSession(configuration、executor、事务)
- mapperInterface,代理接口对象,值为com.lyx.mybatis.dao.StudentMapper,也就是我写的StudentMapper.java接口类

- methodCache:存放查询的缓存,同时methodCache的底层是ConcurrentHashMap。由于缓存里面有多个查询,可能出现多个线程同时查询,从而导致高并发问题,所以通过并发工具类:ConcurrentHashMap
