首页 > 其他分享 >mybatis 查询原理

mybatis 查询原理

时间:2024-07-01 15:30:38浏览次数:1  
标签:var1 String Object 查询 ibatis apache org mybatis 原理

mybatis 所有操作都会通过 sqlSession 来完成

public interface SqlSession extends Closeable {
    <T> T selectOne(String var1);

    <T> T selectOne(String var1, Object var2);

    <E> List<E> selectList(String var1);

    <E> List<E> selectList(String var1, Object var2);

    <E> List<E> selectList(String var1, Object var2, RowBounds var3);

    <K, V> Map<K, V> selectMap(String var1, String var2);

    <K, V> Map<K, V> selectMap(String var1, Object var2, String var3);

    <K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);

    <T> Cursor<T> selectCursor(String var1);

    <T> Cursor<T> selectCursor(String var1, Object var2);

    <T> Cursor<T> selectCursor(String var1, Object var2, RowBounds var3);

    void select(String var1, Object var2, ResultHandler var3);

    void select(String var1, ResultHandler var2);

    void select(String var1, Object var2, RowBounds var3, ResultHandler var4);

    int insert(String var1);

    int insert(String var1, Object var2);

    int update(String var1);

    int update(String var1, Object var2);

    int delete(String var1);

    int delete(String var1, Object var2);

    void commit();

    void commit(boolean var1);

    void rollback();

    void rollback(boolean var1);

    List<BatchResult> flushStatements();

    void close();

    void clearCache();

    Configuration getConfiguration();

    <T> T getMapper(Class<T> var1);

    Connection getConnection();
}

  1. 获取 SqlSessionFactory(SqlSessionFactory 初始化)

    1. org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream),返回的是 DefaultSqlSessionFactory
    2. 里面再调用 parse 方法解析配置文件,构建一个 Configuration 对象(包括全局配置文件和mapper.xml映射文件)
      1. mapper 映射文件中的每个增删改查都会封装成一个 MappedStatement 对象,然后放到 mappedStatements里。mappedStatements 是一个 map,key 是 id,value 是 MappedStatement(configruation.mappedStatements
      2. 所有的 mapper 接口文件解析后的信息都放在 configruation.mapperRegistry 里。 mapperRegistry 里面还有个 knownMappers,这是一个 map 放着每个 mapper 接口和其代理对象的工厂对象,后面会根据这个创建 mapper 接口的代理对象(configruation.mapperRegistry.knownMappers
  2. 获取 SqlSession,里面包含了 Executor 和 Configuration

    1. org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession(),返回的是 DefaultSqlSession

    2. org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource

      private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
              Transaction tx = null;
      
              DefaultSqlSession var8;
              try {
                  Environment environment = this.configuration.getEnvironment();
                  TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
                  tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
                  // 这个是关键,所有数据库操作都是 Executor 完成的
                  Executor executor = this.configuration.newExecutor(tx, execType);
                  var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
              } catch (Exception var12) {
                  Exception e = var12;
                  this.closeTransaction(tx);
                  throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
              } finally {
                  ErrorContext.instance().reset();
              }
      
              return var8;
          }
      
    3. org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)

      public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
              executorType = executorType == null ? this.defaultExecutorType : executorType;
              executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
              // 根据条件创建不同的 executor,默认是 Simple
              Object executor;
              if (ExecutorType.BATCH == executorType) {
                  executor = new BatchExecutor(this, transaction);
              } else if (ExecutorType.REUSE == executorType) {
                  executor = new ReuseExecutor(this, transaction);
              } else {
              	// 这个是默认的
                  executor = new SimpleExecutor(this, transaction);
              }
      		// 如果开启了缓存,再把 executor 包装一下,最终都是通过包装后的 executor 执行 db 操作
              if (this.cacheEnabled) {
                  executor = new CachingExecutor((Executor)executor);
              }
      		// 如果有插件,再包装一下,同上最终使用还是还是包装后的 executor
              Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
              return executor;
          }
      
  3. getMapper 获取代理对象

    1. org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper

      public <T> T getMapper(Class<T> type) {
      	return this.configuration.getMapper(type, this);
      }
      
    2. org.apache.ibatis.session.Configuration#getMapper

      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
          // 刚才说了初始化 SqlSessionFactoryBuilder 的时候设置了 configruation.mapperRegistry 并维护了 knownMappers
          // 这里 getMapper 的就是调用 MapperRegistry 的方法
          return this.mapperRegistry.getMapper(type, sqlSession);
      }
      
    3. org.apache.ibatis.binding.MapperRegistry#getMapper

      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 {
                  // 调用 newInstance 创建对象,这里就不继续点了
                  // 后面步骤也很清晰:通过JDK动态代理创建对象;代理对象里面含有 sqlSession(sqlSession 里面有 executor)
                  return mapperProxyFactory.newInstance(sqlSession);
              } catch (Exception var5) {
                  Exception e = var5;
                  throw new BindingException("Error getting mapper instance. Cause: " + e, e);
              }
          }
      }
      
  4. 根据 Mapper 获取到了对象,就该调用里面的方法了,比如 selectById,现根据方法名判断是否是 Object 的方法,比如 toString、equlas 等,不是 Object 的方法,就把当前方法包装成一个 MapperMethod,传入 SqlSession 来执行这个方法 mapperMethod.execute(this.sqlSession, args)

    public Object execute(SqlSession sqlSession, Object[] args) {
            Object result;
            Object param;
        	// command 有两个属性
        	// 属性1 String name:mapper xml 的 id,也就是 MappedStatement 的 id,也就是 mapper 接口的方法全限定名
        	// 属性2 SqlCommandType type:语句的类型,增删改成哪一种,是一个枚举
            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()) { // 返回 map 怎么执行
                        result = this.executeForMap(sqlSession, args);
                    } else if (this.method.returnsCursor()) { // 返回游标怎么执行
                        result = this.executeForCursor(sqlSession, args);
                    } else {
                        // 处理参数,如果只有一个参数直接返回,如果是多个就返回一个 map,param 里面都是参数信息
                        param = this.method.convertArgsToSqlCommandParam(args);
                        // 参数参数 sqlSession 方法并调用(底层还是会调用 sqlSession.selectList,返回第一个)
                        result = sqlSession.selectOne(this.command.getName(), param);
                        if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
                            result = Optional.ofNullable(result);
                        }
                    }
                    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;
            }
        }
    
  5. org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)

    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        List var5;
        try {
            // 先拿到 MappedStatement,也就是 xml 定义的东西
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            // MappedStatement 传给 executor 的 query 方法。this.wrapCollection(parameter):再次包装参数,集合,map,还是单个参数
            var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception var9) {
            Exception e = var9;
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    
        return var5;
    }
    
  6. org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler) 这个 query 做了什么

    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    	// 这个里面是所有 sql 信息的对象,参数是什么,值是什么,语句是什么(boundSql.getSql能拿到真正执行的sql,这里调试比较有用)
        BoundSql boundSql = ms.getBoundSql(parameter);
        // 构建一个缓存 key,下面查询的时候用这个缓存 key 去查,有就返回,没有就查库
        CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
        // 再调用 query 方法
        return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
    
  7. org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

    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()) {
                    DeferredLoad deferredLoad = (DeferredLoad)var8.next();
                    deferredLoad.load();
                }
    
                this.deferredLoads.clear();
                if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                    this.clearLocalCache();
                }
            }
    
            return list;
        }
    }
    
  8. queryFromDatabase 方法又调用了 doQuery 方法org.apache.ibatis.executor.SimpleExecutor#doQuery

    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        // java.sql 这个包下面的,再接近 jdbc 了
        Statement stmt = null;
    
        List var9;
        try {
            Configuration configuration = ms.getConfiguration();
            // 先创建 Statement 处理器
            StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            // 根据 Statement 处理器拿到 Statement
            stmt = this.prepareStatement(handler, ms.getStatementLog());
            // 再把 Statement 传给 query
            var9 = handler.query(stmt, resultHandler);
        } finally {
            this.closeStatement(stmt);
        }
    
        return var9;
    }
    
  9. 然后参数处理,执行查询,结果映射,关闭连接等

标签:var1,String,Object,查询,ibatis,apache,org,mybatis,原理
From: https://www.cnblogs.com/cryus/p/18278160

相关文章

  • ​RAG与LLM原理及实践(7)--- Chroma query应用层策略及实现原理
    背景Chromaquery底层查询的 query思想是相同的,甚至在vectordb的世界中,都大同小异。如果你有看前面写的  RAG与LLM原理及实践(5)---Chromaquery源码分析应该比较清楚query的运作原理,说直白就是在memory或是disk中通过暴力查询比较与HNSW算法(NSW算法的变种,分层可导航......
  • RAG与LLM原理及实践(6)--- Chroma collection及存储逻辑分析
     背景在chromavectordb的世界中,除了对query的理解,另外就是需要深入理解chroma的运行模式,chroma运行时,提供了 local模式,server-client模式,这些在应用中固然重要,但从实现原理上说,其实就是通过http服务,在固定端口如11344上请求数据。但是在这之前,需要深入了解并理解coll......
  • RAG与LLM原理及实践(4)--- 语义相似度距离衡量的三种方式chroma示例
    语义相似度的计算是一个比较复杂的过程。今天打算先比较详细的介绍下几个相似度的距离衡量算法。相似度的排名衡量,在向量数据库vectordb的query中,被大量使用。还是直接上干货,理解下背后的逻辑和概念比较重要,后面看看源码 chromavectordb是怎么处理这个过程的。1)co......
  • 磐维数据库查询结果按列展示
    磐维数据库中如何实现查询结果按列展示?类似与MySQL数据库的\G效果,可以使用\x命令,以扩展方式显示查询结果。示例如下:postgres=#\xExpandeddisplayison.postgres=#select*frompg_user;-[RECORD1]----+-------------usename|dtpusesysid|20720usecreatedb|0......
  • BeanFactoryAware原理机制
    BeanFactoryAware是Spring框架中的一个接口,它允许一个bean在其初始化时感知到其所在的BeanFactory。这通常用于在bean内部进行一些高级配置或访问Spring容器中的其他bean。简单使用当你实现BeanFactoryAware接口时,你需要实现setBeanFactory(BeanFactoryb......
  • 知识不成体系?这篇Mysql数据库将成为你的解忧杂货店!(子查询)
     欢迎来到@一夜看尽长安花博客,您的点赞和收藏是我持续发文的动力对于文章中出现的任何错误请大家批评指出,一定及时修改。有任何想要讨论的问题可联系我:[email protected]。发布文章的风格因专栏而异,均自成体系,不足之处请大家指正。   专栏:java全栈C&C++PythonAIP......
  • springboot+vue+mybatis农业信息管理_种植员+PPT+论文+讲解+售后
    网络的广泛应用给生活带来了十分的便利。所以把农业信息管理与现在网络相结合,利用java技术建设农业信息管理系统,实现农业信息管理的信息化。则对于进一步提高农业信息管理发展,丰富农业信息管理经验能起到不少的促进作用。农业信息管理系统能够通过互联网得到广泛的、全面的宣......
  • springboot+vue+mybatis奶茶管理系统+PPT+论文+讲解+售后
    由于科学技术的快速发展,人们的生活也与信息时代的发展相关。同时,随着市场化和经济化的发展,国内很多行业已经意识到了这一点,为了提升行业的竞争力,就应当率先把握机会。于是在互联网的默化潜移影响下,餐饮业相关网站就是在这种情况下产生和发展起来的。奶茶在线订购系统是一个面......
  • SSM中Mybatis的配置
    注:数据库连接(此过程不当做本次笔记重点,只做简单概述)1、创建并配置jdbc.properties文件2、通过Druid连接池配置连接数据库3、将数据源(dataSource)注入IOC详细配置一、xml文件与配置类混合配置1、配置logback.xml文件<?xmlversion="1.0"encoding="UTF-8"?><configuration......
  • 降维 (Dimensionality Reduction) 原理与代码实例讲解
    降维(DimensionalityReduction)原理与代码实例讲解作者:禅与计算机程序设计艺术/ZenandtheArtofComputerProgramming关键词:降维技术,数据可视化,特征选择,PCA,t-SNE,SVD,机器学习1.背景介绍1.1问题的由来在数据分析和机器学习领域,面对高维度的数据集是一个普遍且......