后面开始分析sql执行的源码流程
也就是这一部分
一、factory.openSession()
重点关注configuration.newExecutor这个方法,获取事务处理器比较简单,就是获取一个jdbc的事务管理器。
- 这个方法通过传入的执行器类型来创建不同的执行器,有simple、batch、reuse等
- 如果支持缓存的话,会创建CachingExecutor执行器
执行完成之后最后生成了一个DefaultSqlSession,有关DefaultSqlSession,特别要注意一点,它是一个非线程安全的类。
二、获取mapper接口
�
关于knownMappers前面讲过:是一个map,里面存放的是mapper的类型和MapperProxyFactory类。
后面就是调用mapperProxyFactory.newInstance(sqlSession)进行mapper接口的实例化。
最终会拿着mapper接口、代理方法缓存 生成InvokeHandler(用来生成Jdk代理必须要的类,当调用被代理的方法的时候,会调用到InvokeHandler的invokde方法)
最终返回的代理对象就是下图所示:
三、处理查询操作
当我们调用这个查询方法的时候,最终会调用到userProxy的invoke方法
先看cachedInvoker方法,
最终会生成一个PlainMethodInvoker,这个类是MapperProxy的静态内部类
这里会调用到mapperMethod.execute方法, MapperMethod中,command存放的是sql的一些信息,method存放方法的一些信息
public class MapperMethod {
// todo 存放sql的一些信息,其中name属性存放的是“包名、类名、方法名”
private final SqlCommand command;
// todo 方法的签名,主要存放方法的一些信息
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
// todo 处理查询操作
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
// todo 返回多行记录
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
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;
}
在execute方法里面,会处理 sql 的 INSERT(mapper.xml 中的 insert 标签)、UPDATE(mapper.xml 中的 update 标签)、DELETE(mapper.xml 中的 delete 标签)、SELECT(mapper.xml 中的 select 标签)、FLUSH(针对 BatchExecutor 执行器,执行缓存的 Statement)等操作,这里我们仅关注 select 操作
接下来调用DefaultSqlSession.selectList方法来执行
这里会从configuration里面通过接口对应的MappedStatement,通过执行器调用执行,由于我们默认设置了一级缓存,所以会执行到CacheingExecutor.query方法
这个delegate.query最终调用的是SimpleExecutor.query方法
最终会执行到simpleExecutor.doQuery方法
四、总结
本文主要介绍了 mybatis 执行 sql 的流程,介绍的内容如下:
- mybatis 的 sql 执行操作方法在 SqlSession 中,SqlSession 是 mybatis 的执行入口
- XxxMapper 是一个接口,mybatis 基于 jdk 动态代理机制会生成一个代理对象,其 InvocationHandler(具体类为 MapperProxy)的 invoker(…) 方法会获取 mapper.xml 定义的 sql 并执行
- 执行 XxxMapper 方法时,实际调用的是 MapperProxy#invoker(…) 方法,整个方法的执行过程中,会获取 mapper.xml 中的 sql 语句,然后使用执行器(SimpleExecutor、ReuseExecutor、BatchExecutor 等)处理 sql 的执行
- mybatis 提供的 DefaultSqlSession 是非线程安全的,想要线程安全,可以使用 SqlSessionManager
原文地址:https://blog.csdn.net/LittleStar_Cao/article/details/135441483
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_52758.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!