• SqlSession类关系图
  1. MapperFactoryBean 获取SqlSessionTemplate,SqlSessionTemplate的Configuration持有了mapper
 **************************MapperFactoryBean**********************************public T getObject() throws Exception {return this.getSqlSession().getMapper(this.mapperInterface);}**************************SqlSessionTemplate**********************************public <T> T getMapper(Class<T> type) {return this.getConfiguration().getMapper(type, this);}**************************Configuration***************************************public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return this.mapperRegistry.getMapper(type, sqlSession);}
  1. MapperRegistry 注册中心会根据mapper的接口生成代理类
 **************************MapperRegistry***************************************public <T> T getMapper(Class<T> type, SqlSession sqlSession) {MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);if (mapperProxyFactory == null) {throw new BindingException("Type " + type + " is not known to the MapperRegistry.");} else {try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception var5) {throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);}}}
**************************MapperProxyFactory***************************************protected T newInstance(MapperProxy<T> mapperProxy) {return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);}public T newInstance(SqlSession sqlSession) {MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);return this.newInstance(mapperProxy);
  1. 代理类的handler MapperProxy通过反射生成接口的实现方法
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);}if (this.isDefaultMethod(method)) {return this.invokeDefaultMethod(proxy, method, args);}} catch (Throwable var5) {throw ExceptionUtil.unwrapThrowable(var5);}MapperMethod mapperMethod = this.cachedMapperMethod(method);return mapperMethod.execute(this.sqlSession, args);}private MapperMethod cachedMapperMethod(Method method) {MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);if (mapperMethod == null) {mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());this.methodCache.put(method, mapperMethod);}return mapperMethod;}
**************************MapperMethod***************************************//根据查询类型诸如select、delete生成新的方法public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);}
  1. 根据命令模式进行解析执行
**************************MapperMethod***************************************
public Object execute(SqlSession sqlSession, Object[] args) {Object param;Object result;switch(this.command.getType()) {case INSERT:param = this.method.convertArgsToSqlCommandParam(args);result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));break;case UPDATE:param = this.method.convertArgsToSqlCommandParam(args);result = this.rowCountResult(sqlSession.update(this.command.getName(), param));break;case DELETE:param = this.method.convertArgsToSqlCommandParam(args);result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));break;case SELECT:if (this.method.returnsVoid() && this.method.hasResultHandler()) {this.executeWithResultHandler(sqlSession, args);result = null;} else if (this.method.returnsMany()) {result = this.executeForMany(sqlSession, args);} else if (this.method.returnsMap()) {result = this.executeForMap(sqlSession, args);} else if (this.method.returnsCursor()) {result = this.executeForCursor(sqlSession, args);} else {param = this.method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(this.command.getName(), param);}break;case FLUSH:result = sqlSession.flushStatements();break;default:throw new BindingException("Unknown execution method for: " + this.command.getName());}if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");} else {return result;}}
  1. 调用到sqlsession去执行命令,这里对应的是select
**************************MapperMethod***************************************private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {Object param = this.method.convertArgsToSqlCommandParam(args);List result;if (this.method.hasRowBounds()) {RowBounds rowBounds = this.method.extractRowBounds(args);result = sqlSession.selectList(this.command.getName(), param, rowBounds);} else {result = sqlSession.selectList(this.command.getName(), param);}if (!this.method.getReturnType().isAssignableFrom(result.getClass())) {return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result);} else {return result;}}
**************************SqlSessionTemplate**********************************public <E> List<E> selectList(String statement, Object parameter) {return this.selectList(statement, parameter, RowBounds.DEFAULT);}// SqlSessionTemplatede 的代理类(内部类)获取SqlSession的实体类(默认是DefaultSqlSession)了,在invoke SqlSession的接口过程中,会open和colsesession ,session的打开是放在
SqlSessionFactory中管理的private class SqlSessionInterceptor implements InvocationHandler {private SqlSessionInterceptor() {}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);Object unwrapped;try {Object result = method.invoke(sqlSession, args);if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {sqlSession.commit(true);}unwrapped = result;} catch (Throwable var11) {unwrapped = ExceptionUtil.unwrapThrowable(var11);if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);sqlSession = null;Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);if (translated != null) {unwrapped = translated;}}throw (Throwable)unwrapped;} finally {if (sqlSession != null) {SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);}}return unwrapped;}}
  1. 实现类DefaultSqlSession调用executor执行query
 **************************DefaultSqlSession**********************************public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {List var5;try {MappedStatement ms = this.configuration.getMappedStatement(statement);var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);} catch (Exception var9) {throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);} finally {ErrorContext.instance().reset();}return var5;}
  1. 最终会调到BaseExecutor的query方法去操作数据库
**************************BaseExecutor**********************************public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());if (this.closed) {throw new ExecutorException("Executor was closed.");} else {if (this.queryStack == 0 && ms.isFlushCacheRequired()) {this.clearLocalCache();}List list;try {++this.queryStack;list = resultHandler == null ? (List)this.localCache.getObject(key) : null;if (list != null) {this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);} else {list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);}} finally {--this.queryStack;}if (this.queryStack == 0) {Iterator var8 = this.deferredLoads.iterator();while(var8.hasNext()) {BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();deferredLoad.load();}this.deferredLoads.clear();if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {this.clearLocalCache();}}return list;}}private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);List list;try {list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);} finally {this.localCache.removeObject(key);}this.localCache.putObject(key, list);if (ms.getStatementType() == StatementType.CALLABLE) {this.localOutputParameterCache.putObject(key, parameter);}return list;}
  1. 在SimpleExecutor中最终会创建sql 的Statement 打开数据库的连接,调用MySQL的API去执行查询
    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt = null;List var9;try {Configuration configuration = ms.getConfiguration();StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);stmt = this.prepareStatement(handler, ms.getStatementLog());var9 = handler.query(stmt, resultHandler);} finally {this.closeStatement(stmt);}return var9;}private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {Connection connection = this.getConnection(statementLog);Statement stmt = handler.prepare(connection, this.transaction.getTimeout());handler.parameterize(stmt);return stmt;}
  • SQL执行器Executor的类关系图

通过源码分析Mybatis运行原理相关推荐

  1. 通过源码分析MyBatis的缓存

    前方高能! 本文内容有点多,通过实际测试例子+源码分析的方式解剖MyBatis缓存的概念,对这方面有兴趣的小伙伴请继续看下去~ MyBatis缓存介绍 首先看一段wiki上关于MyBatis缓存的介绍 ...

  2. 通过源码分析Mybatis是如何返回数据库生成的自增主键值?

    在Mybatis中,执行insert操作时,如果我们希望返回数据库生成的自增主键值,那么就需要使用到KeyGenerator对象. 需要注意的是,KeyGenerator的作用,是返回数据库生成的自增 ...

  3. datatable如何生成级联数据_通过源码分析Mybatis是如何返回数据库生成的自增主键值?...

    在Mybatis中,执行insert操作时,如果我们希望返回数据库生成的自增主键值,那么就需要使用到KeyGenerator对象. 需要注意的是,KeyGenerator的作用,是返回数据库生成的自增 ...

  4. 通过源码分析Android 的消息处理机制

    2019独角兽企业重金招聘Python工程师标准>>> #通过源码分析Android 的消息处理机制 我们知道,Android应用是通过消息来驱动的,每一个进程被fork之后,都会在 ...

  5. 通过源码分析各种Map(含LinkedHashMap、IdentityHashMap、ConcurrentHashMap)

    [干货预警,强烈建议关注收藏阅读] HashMap HashMap中的树存储 Hashtable(已过时,了解即可) TreeMap LinkedHashMap IdentityHashMap Con ...

  6. 本周两场直播丨通过源码了解openGauss多线程架构;Oracle数据库索引分裂详解。...

    1.管中窥豹之通过源码了解openGauss多线程架构-8月18日20:00 本讲座主要介绍openGauss的多线程架构,通过源码了解线程间通信机制.线程池的原理和优势.如何开启线程池等,力图通过多 ...

  7. 从源码角度分析 Mybatis 工作原理

    作者:vivo互联网服务器团队-Zhang Peng 一.MyBatis 完整示例 这里,我将以一个入门级的示例来演示 MyBatis 是如何工作的. 注:本文后面章节中的原理.源码部分也将基于这个示 ...

  8. Mybatis运行原理及源码解析

    Mybatis源码解析 一.前言 本文旨在mybatis源码解析,将整个mybatis运行原理讲解清楚,本文代码地址: https://github.com/lchpersonal/mybatis-l ...

  9. mybatis源码分析、底层原理

    mybatis用于和数据库交互层面,我们只需定义好Mapper接口,在业务层需要的地方通过@Autowird引入对应的XxxMapper即可,很方便.为什么@Autowird可以从容器中拿到XxxMa ...

最新文章

  1. java适配器模式 场景_Java设计模式之《适配器模式》及应用场景
  2. 为什么docker比VM快?
  3. 微软官宣:史上最贵开发工具 75亿美金收购GitHub
  4. 前端小知识点(3):JavaScript 单线程
  5. Kubernetes在上汽集团云平台及AI方面的应用
  6. C/C++ | Qt 实现爬虫功能,爬取CSDN博客文章
  7. 我的docker随笔13:docker源码编译进阶篇
  8. C# 数组、ArrayList、List、Dictionary的用法与区别
  9. 『学了就忘系列』Linux基础命令 — 搜索操作相关命令
  10. 【学习OpenCV4】如何操作图像中的像素?
  11. 自研数据分析工具——yandas系列一:分析泰坦尼克号沉船事件中的乘客信息表
  12. Kernel启动流程源码解析 1 head.S
  13. python基础-列表
  14. 照度计是什么测量原理
  15. 变态级JAVA程序员面试32问(转)
  16. 在微型计算机中 负数常用()表示,在微型计算机中,负数常用( )表示。
  17. CSDN是一帮穷鬼吗?从来没见过短信认证要客户编写一长串文字发给一个不知名号码的。
  18. “犇牛”踏蹄而来 牛年首“牛”木马大爆发
  19. java求圆的周长、面积
  20. 【Adobe 】Adobe Photoshop2022特别版推荐

热门文章

  1. 码工成长手册:刚毕业的程序员如何快速提升自己?
  2. Ubuntu重启黑屏无法进入GUI桌面
  3. 小马哥--高仿三星G9200 主板型号A208刷机拆机主板图
  4. 名帖330 王羲之 行草《平安帖》《何如帖》《奉橘帖》
  5. 原来苹果手机是这样清理内存的,能腾出大量内存,难怪用这么久还流畅
  6. 猫和老鼠玩象棋,玩了M+N局,猫赢了M局 老鼠赢了N局 NM,而且在整个过程中,猫的得分从来没有超过过老鼠,问共有多少种可能的比赛得分过程
  7. 更改Windows鼠标滑轮滚动方向
  8. 批处理命令更改Windows鼠标滑轮滚动方向
  9. Matlab 极坐标平面 插值,如何在极坐标中进行插值
  10. Flask教程(十六)RESTful-API