zoukankan      html  css  js  c++  java
  • Mybatis

    入口

    public static void statementTest() {
        // 1.0 配置解析入口
        // mybatis-config.xml - Configuration
        // mapper.xml - <Type,MapperProxyFactory>
        // mapper.xml#<select|insert|update|delete> - MappedStatement
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is,null,null);
    
        // 2.0 sqlSession获取(DefaultSqlSession 组合了一个 executor对象,具体的语句执行由executor对象完成)
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            // 3.0 获取代理对象
            KiqiMapper kiqiMapper = sqlSession.getMapper(KiqiMapper.class);
    
            // 4.0 通过代理对象实现sql语句的执行(代理对象方法 -> 触发管理类MapperProxy<T> -> mapperMethod.invoke()中根据statementId和sql类型调用sqlSession方法)
            Kiqi kiqi = kiqiMapper.selectByPrimaryKey(1);
    
            // 4.6 入口,4.0-4.5通过代理对象获取到相应的statementId和type类型,然后调用sqlSession方法
            Kiqi kiqi1 = sqlSession.selectOne(null,null);
    
            System.out.println(kiqi);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }
    

    配置读取 - SqlSessionFactoryBuilder().build();

    ① 读取mybatis-config.xml配置文件,构建configuration对象
    ② 读取Mapper.xml配置文件,创建Type-MapperProxyFactory<T>映射,MapperProxyFactory用于生成Mapper代理对象
    ③ 读取Mapper.xml - insert|update|delete|select标签,构建MappedStatement对象,用于语句执行
    mybatis 会话工厂创建流程

    创建会话 - sqlSessionFactory.openSqlSession();

      private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        // 2.1 获取SqlSession
        Transaction tx = null;
        try {
          final Environment environment = configuration.getEnvironment();
          // 1. 获取事务工厂(事务工厂在config配置文件的environment标签中,通过配置文件设置 --- <transactionManager type="JDBC"/>)
          final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
          // 2. 创建事务对象
          tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
          // 3. 根据事务工厂和执行器配置,创建执行器
          final Executor executor = configuration.newExecutor(tx, execType);
          // 4. 创建DefaultSqlSession
          return new DefaultSqlSession(configuration, executor, autoCommit);
        } catch (Exception e) {
          closeTransaction(tx); // may have fetched a connection so lets call close()
          throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
        } finally {
          ErrorContext.instance().reset();
        }
      }
    

    获取mapper代理对象 - session.getMapper();

    ① 使用Type从configuration中获取到对应的MapperProxyFactory对象
    ② MapperProxyFactory创建MapperProxy对象(InvocationHandler接口实现类),并以此创建代理对象

      @SuppressWarnings("unchecked")
      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        // 3.2 在对mapper.xml文件解析时,构建了classType(namespace)与mapperProxyFactory的映射
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
        if (mapperProxyFactory == null) {
          throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        }
        try {
          // 3.3 创建代理对象
          return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception e) {
          throw new BindingException("Error getting mapper instance. Cause: " + e, e);
        }
      }
    
    public class MapperProxyFactory<T> {
    
      private final Class<T> mapperInterface;
      private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
      
      // ...
    
      @SuppressWarnings("unchecked")
      protected T newInstance(MapperProxy<T> mapperProxy) {
        // 1:类加载器、2:被代理类实现的接口、3:实现了 InvocationHandler 的触发管理类
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
      }
    
      public T newInstance(SqlSession sqlSession) {
        // 3.4 构建实现了 InvocationHandler接口的 触发管理类(特殊点:未封装被代理对象)
        final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
      }
    }
    

    执行mapper代理方法 - mapper.selectAll()

    ① 根据被调用的代理对象,调用对应的sqlSession方法 - eg: sqlSession.selectList(commandName,param);
    调用代理对象方法 -> MapperProxy<T>.invoke()方法 -> MapperMethodInvoker.invoke()方法 -> mapperMethod.execute()方法 -> sqlSession方法

    ② sqlSession委托executor对象执行sql语句,先完成代理逻辑,再判断缓存是否存在,不存在则进入数据库查询逻辑
    sqlSession.selectList() -> Executor.query() -> **intercept代理对象.intercept()** -> CachingExecutor代理对象查询二级缓存 -> baseExecutor查询一级缓存 -> 数据库查询

    ③ 数据库查询:BaseExecutor.queryFromDatabase() - 实质为对jdbc的封装

    1. 构建三大对象(StatementHandler,ParameterHandler 和 resultSetHandler)
    2. 从transaction对象中获取数据库链接connection
    3. 获取PrepareStatement对象
    4. 调用ParameterHandler.setParameters()方法,为pstm设置参数
    5. JDBC:pstm.execute(sql);
    6. resultSetHandler.handleResultSets(pstm),完成结果集处理
      Mybatis SQL调用执行流程

    欢迎疑问、期待评论、感谢指点 -- kiqi,愿同您为友

    -- 星河有灿灿,愿与之辉

  • 相关阅读:
    bzoj1103[POI2007]大都市meg
    bzoj1098[POI2007]办公楼biu
    bzoj1102[POI2007]山峰和山谷Grz
    POI刷题记录
    语法-指针
    dp-最长公共子序列
    如何判断素数
    C++的map用法
    stl-优先队列
    C++和Java的stack语法
  • 原文地址:https://www.cnblogs.com/kiqi/p/14368097.html
Copyright © 2011-2022 走看看