MyBatis源码解读(4)——SqlSession(上)
在上一篇博客中提到MyBatis是如何实现代理类MapperProxy,并抛出了一个问题——是怎么执行一个具体的sql语句的,在文末中提到了MapperMethod的execute采用命令模式来判断是何种sql语句,并将具体语句的执行交由SqlSession处理。所以此篇博客正是要讲到SqlSession。
在SqlSession接口中包含了所有可能执行的sql语句在这里不一一列举,请参考org.apache.ibatis.session.SqlSession源码。DefaultSqlSession是SqlSession的实现类,所以我们重点关注DefaultSqlSession类。在上一篇博客中提到了我们将选择MapperProxy的executeForMany方法。在此方法中调用了SqlSession.<E>selectList方法。所以我们来看看org.apache.ibatis.session.default.DefaultSqlSession类的selectList方法。
//org.apache.ibatis.session.defaults.DefaultSqlSession
……
@Override
public <E> List<E> selectList(String statement) {
return this.selectList(statement, null);
} @Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
} @Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
……
我们看到关于selectList有三个重载方法,最后调用的都是public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds)。在此方法中第一个参数为String类型且命名为statement,第二个参数为Object命名为parameter,回到MapperMethod。
//org.apache.ibatis.binding.MapperMethod
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.<E>selectList(command.getName(), param, rowBounds); //注意传递了什么参数进来
} else {
result = sqlSession.<E>selectList(command.getName(), param);
}
// issue #510 Collections & arrays support
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}
第7行代码可以看到传递了什么参数进来,跟踪command.getName()是怎么来的。
private final SqlCommand command;
看来是一个叫做SqlCommand的变量,进而我们可以发现这个SqlCommand是MapperMethod的静态内部类。
//org.apache.ibatis.binding.MapperMethod
public static class SqlCommand { private final String name;
private final SqlCommandType type; public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
String statementName = mapperInterface.getName() + "." + method.getName(); //获取接口+方法名
MappedStatement ms = null; //定义一个MappedStatement,这个MapperedStatement稍后介绍
if (configuration.hasStatement(statementName)) { //从Configuration对象查找是否有这个方法的全限定名称
ms = configuration.getMappedStatement(statementName); //有,则根据方法的全限定名称获取MappedStatement实例
} else if (!mapperInterface.equals(method.getDeclaringClass())) { // issue #35//如果没有在Configuration对象中找到这个方法,则向上父类中获取全限定方法名
String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName();
if (configuration.hasStatement(parentStatementName)) { //在向上的父类查找是否有这个全限定方法名
ms = configuration.getMappedStatement(parentStatementName); //有,则根据方法的全限定名称获取MappedStatement实例
}
}
if (ms == null) {
if(method.getAnnotation(Flush.class) != null){
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException("Invalid bound statement (not found): " + statementName);
}
} else {
name = ms.getId(); //这个ms.getId,其实就是我们在mapper.xml配置文件中配置一条sql语句时开头的<select id="……"……,即是接口的该方法名全限定名称
type = ms.getSqlCommandType(); //显然这是将sql是何种类型(insert、update、delete、select)赋给type
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
} public String getName() {
return name;
} public SqlCommandType getType() {
return type;
}
}
大致对MapperMethod的解读到此,再次回到DefaultSqlSession中,到这里可能稍微有点混乱。画个图来理解这一段,希望能帮助理解。
这次又一次回到了DefaultSqlSession.selectList。此处不再贴出selectList所有方法,而是只贴出一句,根据接口方法的全限定名称获取MappedStatement。
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
在获取到MappedStatement后,碰到了第一个SqlSession下的四大对象之一:Executor执行器。看来还是没有讲到SqlSession,再放到下一节吧。可以思考下这个MappedStatement是什么意思,望文生义就能猜出个大概。
这是一个能给程序员加buff的公众号
MyBatis源码解读(4)——SqlSession(上)的更多相关文章
- MyBatis源码解读(3)——MapperMethod
在前面两篇的MyBatis源码解读中,我们一路跟踪到了MapperProxy,知道了尽管是使用了动态代理技术使得我们能直接使用接口方法.为巩固加深动态代理,我们不妨再来回忆一遍何为动态代理. 我相信在 ...
- spring IOC DI AOP MVC 事务, mybatis 源码解读
demo https://gitee.com/easybao/aop.git spring DI运行时序 AbstractApplicationContext类的 refresh()方法 1: pre ...
- Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?
Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的? 如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...
- Mybatis源码解读-SpringBoot中配置加载和Mapper的生成
本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...
- Mybatis源码解读-插件
插件允许对Mybatis的四大对象(Executor.ParameterHandler.ResultSetHandler.StatementHandler)进行拦截 问题 Mybatis插件的注册顺序 ...
- MyBatis源码解读之延迟加载
1. 目的 本文主要解读MyBatis 延迟加载实现原理 2. 延迟加载如何使用 Setting 参数配置 设置参数 描述 有效值 默认值 lazyLoadingEnabled 延迟加载的全局开关.当 ...
- MyBatis源码解读(1)——SqlSessionFactory
在前面对MyBatis稍微有点了解过后,现在来对MyBatis的源码试着解读一下,并不是解析,暂时定为解读.所有对MyBatis解读均是基于MyBatis-3.4.1,官网中文文档:http://ww ...
- 【转】Mybatis源码解读-设计模式总结
原文:http://www.crazyant.net/2022.html?jqbmtw=b90da1&gsjulo=kpzaa1 虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开 ...
- Mybatis源码分析之SqlSession和Excutor(二)
通过上一篇文章的分析我们,我初步了解了它是如何创建sessionFactory的(地址:Mybatis源码分析之SqlSessionFactory(一)), 今天我们分析下Mybatis如何创建Sql ...
- Mybatis源码解读-设计模式总结
虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开发中很少遇到,Mybatis源码中使用了大量的设计模式,阅读源码并观察设计模式在其中的应用,能够更深入的理解设计模式. Mybatis至少 ...
随机推荐
- 关于commonjs,AMD,CMD之间的异同
1.简介 随着前端业务复杂度的增加,模块化成为一个大的趋势.而在ES6还未被浏览器所支持的情况下,commonjs作为ES6中标准模块加载方案,在客服端中的支持情况并不好,现在在客服端中有2中模块化的 ...
- Java基础之IO框架
一.流的概念 流(stream)的概念源于UNIX中管道(pipe)的概念.在UNIX中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备.外部文件等. ...
- 手机自动化测试:Appium源码分析之跟踪代码分析五
手机自动化测试:Appium源码分析之跟踪代码分析五 手机自动化测试是未来很重要的测试技术,作为一名测试人员应该熟练掌握,POPTEST举行手机自动化测试的课程,希望可以训练出优秀的手机测试开发工 ...
- 手机自动化测试:appium源码分析之bootstrap七
手机自动化测试:appium源码分析之bootstrap七 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.poptest测试 ...
- GPU加速有坑?
大多数人都知道有动画的地方可以使用GPU来加速页面渲染. 例如,做优化的时候,将使用left和top属性的动画修改成使用transform属性的CSS动画.或者听到别人教你使用transform:tr ...
- mysql常用技能分享
一,MySQL查询的五种子句: 1,where(条件查询),常用的运算符: ①比较运算符 > , < , = , != , >= , <= , in( ) , between ...
- 关于 centos 7系统,iptables透明网桥实现【转载请注明】
首先建立网桥:(使用bridge) 示例 桥接eth0 与 eth1 网口 /sbin/modprobe bridge /usr/sbin/brctl addbr br0 /sbin/ifup ...
- D3D Learning_01_CreateWindow
// Learn_01_CreateWindow.cpp : Defines the entry point for the application. // #include "stdafx ...
- T-SQL编程中的异常处理-异常捕获(catch)与抛出异常(throw)
本文出处: http://www.cnblogs.com/wy123/p/6743515.html T-SQL编程与应用程序一样,都有异常处理机制,比如异常的捕获与异常的抛出,本文简单介绍异常捕获与异 ...
- 微信公众号、H5、APP三者各有什么优势?
昨天给大家分享了一个现在很热的H5,众所周知,当下H5手机网站.微信公众号.APP这三种载体都越来越火了,而且三者都有各自的一些优势和劣势. HTML5(H5) H5之所以能引发如此广泛的效应,根本在 ...