初看Mybatis 源码 (三) SQL是怎么执行的
前面说到Java动态代理,Mybatis通过这种方式实现了我们通过getMapper方式得到的Dao接口,可以直接通过接口的没有实现的方法来执行sql。
AuthUserDao mapper = session.getMapper(AuthUserDao.class);
getMapper方法到底做了什么。跟踪getMapper方法,进入到 MapperProxyFactory 类的 newInstance(SqlSession sqlSession) 方法。
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
看过上一篇的例子,我们知道。最后是通过Proxy.newProxyInstance 来实现切入sql的。他的实现在MapperProxy的 invoke 方法里面。看下invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
简单来说,在invoke里面做了如下事情:
1. 通过我们调用的方法,如本例中的 selectAuthUserByName ,接口名来组合成语句。本例中是 com.mybatis.dao.AuthUserDao.selectAuthUserByName 。其实使用过sqlSession的selectOne(String statmet)之类的语句都知道。这个可以唯一定位到我们在sql映射文件中配置的sql语句
2. 通过返回值类型,定位到的语句的类型。确定最后应该执行的方法。是执行查询、删除、添加、修改等等。
看下mybatis的是如何做的:
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
if (SqlCommandType.INSERT == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
} else if (SqlCommandType.UPDATE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
} else if (SqlCommandType.DELETE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
} else if (SqlCommandType.SELECT == command.getType()) {
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
} else {
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
可以看到的是,他是通过我们在sql配置文件中的语句类型来判断是执行哪种操作。然后通过返回类型来确定查询是查一条还是查多条记录。最后这种操作的方式,也是回归到了sqlSession中的CRUD的操作的方法。
下面看下,一条sql语句到底是怎么执行的?我们知道Mybatis其实是对JDBC的一个封装。假如我执行
session.update("com.mybatis.dao.AuthUserDao.updateAuthUserEmailByName", test@email.com);
语句,追踪下来,Executor、 BaseStatementHandler等等。在 SimpleExecutor 中有如下代码:
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
1. 首先获取相关配置信息,这个在初始化时,从配置文件中解析而来
2. 新建了一个handler
3. 做了执行statement之前的准备工作。看看准备了些什么,跟踪代码,最后进入了DataSource类的doGetConnection方法,该方法做如下操作:
private Connection doGetConnection(Properties properties) throws SQLException {
initializeDriver();
Connection connection = DriverManager.getConnection(url, properties);
configureConnection(connection);
return connection;
}
private synchronized void initializeDriver() throws SQLException {
if (!registeredDrivers.containsKey(driver)) {
Class<?> driverType;
try {
if (driverClassLoader != null) {
driverType = Class.forName(driver, true, driverClassLoader);
} else {
driverType = Resources.classForName(driver);
}
// DriverManager requires the driver to be loaded via the system ClassLoader.
// http://www.kfu.com/~nsayer/Java/dyn-jdbc.html
Driver driverInstance = (Driver)driverType.newInstance();
DriverManager.registerDriver(new DriverProxy(driverInstance));
registeredDrivers.put(driver, driverInstance);
} catch (Exception e) {
throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
}
}
}
原来是通过prepareStatement 来执行了 我们初始化jdbc的操作。Class.forName DriverManager.getConnection. 这两步是在这里面完成的。
4. 将执行sql的部分交给handler
继续跟踪handler 可以看到SimpleStatementHandler 中。如下执行这个update语句
public int update(Statement statement)
throws SQLException {
String sql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
int rows;
if (keyGenerator instanceof Jdbc3KeyGenerator) {
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) {
statement.execute(sql);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
statement.execute(sql);
rows = statement.getUpdateCount();
}
return rows;
}
这边就完成了statement的操作,整个过程就是我们Jdbc的过程。原来真的就是对JDBC的简单封装。
其实Mybatis的整个执行过程,理解起来分为如下几个过程:
1. 加载配置文件
2. 解析配置文件,从配置文件中解析出来 datasource、mapper文件、事务配置等等。将配置信息保存在对象内
3. 调用相关语句,执行sql。在执行的方法中分别完成JDBC的一系列操作。
初看Mybatis 源码 (三) SQL是怎么执行的的更多相关文章
- 初看Mybatis 源码 (二) Java动态代理类
先抛出一个问题,用过Mybatis的都知道,我们只需要定义一个Dao的接口,在里面写上一些CRUD相关操作,然后配置一下sql映射文件,就可以达到调用接口中的方法,然后执行sql语句的效果,为什么呢? ...
- 初看Mybatis 源码 (一)
Mybatis 的使用,首先需要构建一个SqlSessionFactory 实例.而该实例可以通过SqlSessionFactoryBuilder来创建. String resource = &quo ...
- MyBatis 源码篇-SQL 执行的流程
本章通过一个简单的例子,来了解 MyBatis 执行一条 SQL 语句的大致过程是怎样的. 案例代码如下所示: public class MybatisTest { @Test public void ...
- 精尽MyBatis源码分析 - SQL执行过程(三)之 ResultSetHandler
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- MyBatis 源码分析 - SQL 的执行过程
* 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析 ...
- 精尽MyBatis源码分析 - SQL执行过程(四)之延迟加载
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- MyBatis源码分析-SQL语句执行的完整流程
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- Spring mybatis源码篇章-sql mapper配置文件绑定mapper class类
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-MybatisDAO文件解析(二) 背景知识 MappedStatement是mybatis操作sql ...
- spring事务源码分析结合mybatis源码(三)
下面将结合mybatis源码来分析下,这种持久化框架是如何对connection使用,来达到spring事务的控制. 想要在把mybatis跟spring整合都需要这样一个jar包:mybatis-s ...
随机推荐
- Part 1: Setting up ARM GNU tool chain
ARM Build Tools GNU Tools for ARM Embedded Processors. GNU Make for Windows. GNU Tools for ARM Embed ...
- 02-oracle字符函数
字符函数(scott/tiger 登陆) --upper(col name)将字符大写 --lower(col name)将字符小写 --initcap(col name)字符串的首字母大写,其余小写 ...
- 2019.04.19 读书笔记 比较File.OpenRead()和File.ReadAllBytes()的差异
最近涉及到流的获取与转化,终于要还流的债了. 百度了一下,看到这样的两条回复,于是好奇心,决定看看两种写法的源码差异. 先来看看OpenRead() public static FileStream ...
- python pandas使用chunksize异步拆分固定行数的文件
import pandas as pd import asyncio from collections import defaultdict collect = defaultdict(list) # ...
- 爬虫--XPATH解析
今天说一下关于爬取数据解析的方式---->XPATH,XPATH是解析方式中最重要的一种方式 1.安装:pip install lxml 2.原理 1. 获取页面源码数据 2.实例化一个etr ...
- SQLite3开发接口函数详解
SQLite3是SQLite一个全新的版本,它虽然是在SQLite 2.8.13的代码基础之上开发的,但是使用了和之前的版本不兼容的数据库格式和API. SQLite3是为了满足以下的需求而开发的: ...
- btn按钮事件
1.用Delegate 和 Event 来定义一个通用类来处理事件 (观察者模式) using System.Collections; using System.Collections.Generic ...
- input获得焦点时改变placeholder文本的样式
HTML: <input type="text" placeholder="sample text"/> CSS: input::-webkit-i ...
- 如何正确且高效地中文汉化Spyder 2 或 Spyder3(图文详解)(博主推荐)
不多说,直接上干货! 汉化下载和教程页面 : https://github.com/kingmo888/Spyder_Simplified_Chinese 汉化文件最新版直接下载 : https: ...
- Cucumber capybara 每个Scenario登陆一次
hook.rb中添加: After do |scenario| Capybara.current_session.instance_variable_set(:@touched, false)end ...