zoukankan      html  css  js  c++  java
  • Mybatis原生源码解析

    原始的JDBC操作数据库,请参考Java JDBC连接Oracle

    一、工程搭建

    工程结构如下

    1、引入jar  mybatis-3.2.3.jar 和mysql-connector-java-5.1.25.bin.jar

    2、使用Mysql创建表

    CREATE TABLE `user` (
      `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
      `name` VARCHAR(64) NOT NULL DEFAULT '',
      `dept` VARCHAR(254) NOT NULL DEFAULT '',
      `website` VARCHAR(254) DEFAULT '',
      `phone` VARCHAR(16) NOT NULL DEFAULT '',
      PRIMARY KEY (`id`)
    ) ENGINE=INNODB AUTO_INCREMENT=2 ;
    
    
    INSERT INTO `user` VALUES ('1', 'larry', 'IT', 'http://www.baidu.com', '13688889999');
    

      

    3、创建User实体类

    public class User {
        private int id;
        private String name;
        private String dept;
        private String phone;
        private String website;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getDept() {
            return dept;
        }
    
        public void setDept(String dept) {
            this.dept = dept;
        }
    
        public String getPhone() {
            return phone;
        }
    
        public void setPhone(String phone) {
            this.phone = phone;
        }
    
        public String getWebsite() {
            return website;
        }
    
        public void setWebsite(String website) {
            this.website = website;
        }
    }
    

      

    4、resources/configs/下创建Configure.xml

    mybatis 配置文件,用来建立sessionFactory。里面主要包含了数据库连接,还有Java类对应的别名

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <typeAliases>
            <typeAlias alias="User2" type="com.example.mybatis.model.User" />
        </typeAliases>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
                    <property name="driver"  value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper resource="mapper/User.xml" />
        </mappers>
    </configuration>  

    这里<mapper resource="mapper/User.xml" /> 要映射类的xml配置文件

    5、resources/mapper下创建User.xml

    包含了各种SQL语句

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.mybatis.dao.UserMapper">
        <select id="getUserById" parameterType="int" resultType="User2">
            select * from user where id = #{id}
        </select>
    </mapper>
    

      

    6、创建接口com.example.mybatis.dao.UserMapper

    public interface UserMapper {
        User getUserById(int id);
    }
    

      

    7、创建测试类

    public class MyBatisTest1 {
    
        private static SqlSessionFactory sqlSessionFactory;
        private static Reader reader;
    
        static {
            try {
                reader = Resources.getResourceAsReader("config/Configure.xml");
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
        public static  SqlSessionFactory getSession(){
            return  sqlSessionFactory;
        }
    
        public static void main(String[] args) {
            SqlSession session = sqlSessionFactory.openSession();
            try {
               User user =  (User)session.selectOne("com.example.mybatis.dao.UserMapper.getUserById",1 ) ;
               if(user != null){
                   System.out.println("name is : " + user.getName() + ",所属部门: " + user.getDept());
               }
            }finally {
                session.close();
            }
        }
    }
    

      

    8、显示

    二、源码解析

    通过前面的步骤,关键步骤如下

      // 1.读取mybatis配置文件,并生成SQLSessionFactory
     reader = Resources.getResourceAsReader("config/Configure.xml");
      // 2.获取session,主要的CRUD操作均在SqlSession中提供
      SqlSession session = sqlSessionFactory.openSession();
     // 3.执行查询操作
      // 该方法包括三个步骤:封装入参数、执行查询、封装结果为对象类型
      User user =  (User)session.selectOne("com.example.mybatis.dao.UserMapper.getUserById",1 ) ;
    

     

    1、 Resources.getResourceAsReader("config/Configure.xml");

    public static Reader getResourceAsReader(String resource) throws IOException {
            InputStreamReader reader;
    	//默认为null
            if (charset == null) {
                reader = new InputStreamReader(getResourceAsStream(resource));
            } else {
                reader = new InputStreamReader(getResourceAsStream(resource), charset);
            }
    
            return reader;
        }
    
        //getResourceAsStream方法
        public static InputStream getResourceAsStream(String resource) throws IOException {
            return getResourceAsStream((ClassLoader)null, resource);
        }
        
        //getResourceAsStream方法
        public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
            InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
            if (in == null) {
                throw new IOException("Could not find resource " + resource);
            } else {
                return in;
            }
        }
    
       //ClassLoaderWrapper.getResourceAsStream方法
      InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
        for (ClassLoader cl : classLoader) {
          if (null != cl) {
    
            // 获得资源
            InputStream returnValue = cl.getResourceAsStream(resource);
    
            // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
            if (null == returnValue) returnValue = cl.getResourceAsStream("/" + resource);
    
            if (null != returnValue) return returnValue;
          }
        }
        return null;
      }
    

      

    总结:通过ClassLoader.getResourceAsStream()获取指定路径下的Resource

    2、获取sqlSessionFactory 

      sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);  
      //build方法
      public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
        try {
          XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
          //重点是这个方法 实现了parser.parse()解析xml,build创建sqlSessionFactory
          return build(parser.parse());
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error building SqlSession.", e);
        } finally {
          ErrorContext.instance().reset();
          try {
            reader.close();
          } catch (IOException e) {
            // Intentionally ignore. Prefer previous error.
          }
        }
      }
    

      

    1) 首先是parser.parse()方法

    public Configuration parse() {
        if (parsed) {
          throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        }
        parsed = true;
        parseConfiguration(parser.evalNode("/configuration"));
        return configuration;
      }
    
      private void parseConfiguration(XNode root) {
        try {
          //是对各个节点进行解析
          propertiesElement(root.evalNode("properties")); //issue #117 read properties first
          typeAliasesElement(root.evalNode("typeAliases"));
          pluginElement(root.evalNode("plugins"));
          objectFactoryElement(root.evalNode("objectFactory"));
          objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
          settingsElement(root.evalNode("settings"));
          environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
          databaseIdProviderElement(root.evalNode("databaseIdProvider"));
          typeHandlerElement(root.evalNode("typeHandlers"));
          //重点看下这个方法
          mapperElement(root.evalNode("mappers"));
        } catch (Exception e) {
          throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
        }
      }
    
    
    private void mapperElement(XNode parent) throws Exception {
        if (parent != null) {
          for (XNode child : parent.getChildren()) {
            if ("package".equals(child.getName())) {
              String mapperPackage = child.getStringAttribute("name");
              configuration.addMappers(mapperPackage);
            } else {
    	  //1、获得resource信息,也就是对应的mapper.xml,这里是mapper/User.xml
              String resource = child.getStringAttribute("resource");
              String url = child.getStringAttribute("url");
              String mapperClass = child.getStringAttribute("class");
              if (resource != null && url == null && mapperClass == null) {
    	    //2.解析对应的User.xml
                ErrorContext.instance().resource(resource);
                InputStream inputStream = Resources.getResourceAsStream(resource);
                XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
    	    //3、将解析出来的Mapper对象添加到Configuration中
                mapperParser.parse();
              } else if (resource == null && url != null && mapperClass == null) {
                ErrorContext.instance().resource(url);
                InputStream inputStream = Resources.getUrlAsStream(url);
                XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
                mapperParser.parse();
              } else if (resource == null && url == null && mapperClass != null) {
                Class<?> mapperInterface = Resources.classForName(mapperClass);
                configuration.addMapper(mapperInterface);
              } else {
                throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
              }
            }
          }
        }
      }
    

      总结:通过解析configuration.xml文件,获取其中的Environment、Setting,mappers下的所有<mapper>解析出来之后添加到Configuration。

    2)、生成一个SQLSessionFactory

    public SqlSessionFactory build(Configuration config) {
    
    return new DefaultSqlSessionFactory(config);
    
    }
       
    

      

    3、sqlSessionFactory.openSession(); 开启一个sqlSession

      public SqlSession openSession() {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
      }
    
      private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
        try {
          final Environment environment = configuration.getEnvironment();
          //1、transactionFactory,这里为JdbcTransactionFactory
          final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
          //2、创建一个transaction
          tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
          //3、创建一个Executor 这里为SimpleExecutor,主要的CRUD操作就是再此处完成的
          final Executor executor = configuration.newExecutor(tx, execType, autoCommit);
          //4、将Executor和configuration作为参数,封装到DefaultSqlSession
          return new DefaultSqlSession(configuration, executor);
        } 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();
        }
      }
    

      

    1) TransactionFactory ,主要用来生成transaction的工厂

    public interface TransactionFactory {
      void setProperties(Properties props);
      Transaction newTransaction(Connection conn);
      Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
    
    }
    

      

    2) Transaction

    public interface Transaction {
      Connection getConnection() throws SQLException;
      void commit() throws SQLException;
      void rollback() throws SQLException;
      void close() throws SQLException;
    }  

    可以看到getConnection() 就是返回的java.sql.Connection, 并且还有commint和rollback等操作

     3)Executor

    该接口定义了CRUD操作

    public interface Executor {
    
      ResultHandler NO_RESULT_HANDLER = null;
    
      int update(MappedStatement ms, Object parameter) throws SQLException;
    
      <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
    
      <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
    
      List<BatchResult> flushStatements() throws SQLException;
    
      void commit(boolean required) throws SQLException;
    
      void rollback(boolean required) throws SQLException;
    
      CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
    
      boolean isCached(MappedStatement ms, CacheKey key);
    
      void clearLocalCache();
    
      void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
    
      Transaction getTransaction();
    
      void close(boolean forceRollback);
    
      boolean isClosed();
    
    }
    

      

    4、session.selectOne的执行过程

     public <T> T selectOne(String statement, Object parameter) {
        // 调用selectList
        List<T> list = this.<T>selectList(statement, parameter);
        if (list.size() == 1) {
          return list.get(0);
        } else if (list.size() > 1) {
          throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
          return null;
        }
      }
    
    
    
      public <E> List<E> selectList(String statement, Object parameter) {
        return this.selectList(statement, parameter, RowBounds.DEFAULT);
      }
    
      public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        try {
          //1、获取MappedStatement,里面封装了每一个CRUD操作对应的详细信息 
          MappedStatement ms = configuration.getMappedStatement(statement);
          //2、executor的实现类为CachingExecutor
          List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
          return result;
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
        } finally {
          ErrorContext.instance().reset();
        }
      }
    

      

    5、CachingExecutor.query方法

     public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
        return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
      }
    
      public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        Cache cache = ms.getCache();
        if (cache != null) {
          flushCacheIfRequired(ms);
          if (ms.isUseCache() && resultHandler == null) { 
            ensureNoOutParams(ms, parameterObject, boundSql);
            if (!dirty) {
              cache.getReadWriteLock().readLock().lock();
              try {
                @SuppressWarnings("unchecked")
                List<E> cachedList = (List<E>) cache.getObject(key);
                if (cachedList != null) return cachedList;
              } finally {
                cache.getReadWriteLock().readLock().unlock();
              }
            }
            List<E> list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
            tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
            return list;
          }
        }
        //重点是这句,默认实现为BaseExecutor
        return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
      }
    
    
    //BaseExecutor的query方法
      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 (closed) throw new ExecutorException("Executor was closed.");
        if (queryStack == 0 && ms.isFlushCacheRequired()) {
          clearLocalCache();
        }
        List<E> list;
        try {
          queryStack++;
          list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
          if (list != null) {
            handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
          } else {
    	//重点是这里
            list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
          }
        } finally {
          queryStack--;
        }
        if (queryStack == 0) {
          for (DeferredLoad deferredLoad : deferredLoads) {
            deferredLoad.load();
          }
          deferredLoads.clear(); // issue #601
          if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
            clearLocalCache(); // issue #482
          }
        }
        return list;
      }
    
    
    
    
      private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        List<E> list;
        localCache.putObject(key, EXECUTION_PLACEHOLDER);
        try {
          //重点是这里,是一个抽象方法,由SimpleExecutor实现
          list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
          localCache.removeObject(key);
        }
        localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
          localOutputParameterCache.putObject(key, parameter);
        }
        return list;
      }
    
    
    //SimpleExecutor的doQuery方法
      public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;
        try {
         
          Configuration configuration = ms.getConfiguration();
           //1、StatementHandler 分装了JDBC Statement操作,如设置参数,将Statement结果转换成List集合
          StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql);
          //2、封装StatementHandler 参数
          stmt = prepareStatement(handler, ms.getStatementLog());
          //执行execute操作
          return handler.<E>query(stmt, resultHandler);
        } finally {
          closeStatement(stmt);
        }
      }
    

      1) configuration.newStatementHandler

      public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
        return statementHandler;
      }
    
    
      //RoutingStatementHandler构造方法
      public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    
        switch (ms.getStatementType()) {
          case STATEMENT:
            delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
          case PREPARED:
        	//默认实现
            delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
          case CALLABLE:
            delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
          default:
            throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
        }
    
      }
    

      

     2) prepareStatement

    功能: 获取Statement; 封装PreparedStatement参数

      private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;
        //1、获取java.sql.Connection
        Connection connection = getConnection(statementLog);
        //2、获取对应的statement
        stmt = handler.prepare(connection);
        //3、封装参数
        handler.parameterize(stmt);
        return stmt;
      }
    

      

    *进入handler.prepare(connection)获取Statement

    //BaseStatementHandler.prepare
      public Statement prepare(Connection connection) throws SQLException {
        ErrorContext.instance().sql(boundSql.getSql());
        Statement statement = null;
        try {
          //关键是这里
          statement = instantiateStatement(connection);
          setStatementTimeout(statement);
          setFetchSize(statement);
          return statement;
        } catch (SQLException e) {
          closeStatement(statement);
          throw e;
        } catch (Exception e) {
          closeStatement(statement);
          throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
        }
      }
    
    //BaseStatementHandler.instantiateStatement
      protected Statement instantiateStatement(Connection connection) throws SQLException {
        String sql = boundSql.getSql();
        if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
          String[] keyColumnNames = mappedStatement.getKeyColumns();
          if (keyColumnNames == null) {
            return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
          } else {
            return connection.prepareStatement(sql, keyColumnNames);
          }
        } else if (mappedStatement.getResultSetType() != null) {
          return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
        } else {
          //默认实现,直接对应传统JDBC方式的从connection中获取PreparedStatement
          return connection.prepareStatement(sql);
        }
      }
    

      

    * handler.parameterize(stmt);封装参数

      public void parameterize(Statement statement) throws SQLException {
        delegate.parameterize(statement);
      }
    
      public void parameterize(Statement statement) throws SQLException {
        parameterHandler.setParameters((PreparedStatement) statement);
      }
    
    
    public void setParameters(PreparedStatement ps) throws SQLException {
        ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
        //1、parameterMappings 包含了需要拼装的参数
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings != null) {
          MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);
          for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            if (parameterMapping.getMode() != ParameterMode.OUT) {
              Object value;
    	  //2、获取参数名称
              String propertyName = parameterMapping.getProperty();
              //3、获取参数值
    	  if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
                value = boundSql.getAdditionalParameter(propertyName);
              } else if (parameterObject == null) {
                value = null;
              } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                value = parameterObject;
              } else {
                value = metaObject == null ? null : metaObject.getValue(propertyName);
              }
    	  //4、获取参数对应的类型处理器
              TypeHandler typeHandler = parameterMapping.getTypeHandler();
              JdbcType jdbcType = parameterMapping.getJdbcType();
              if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
              //5、对应的封装参数操作还是委托给TypeHandle处理
    	  typeHandler.setParameter(ps, i + 1, value, jdbcType);
            }
          }
        }
      }
    
    
    //BaseTypeHandler.setParameter
      public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) {
          if (jdbcType == null) {
            throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
          }
          try {
            ps.setNull(i, jdbcType.TYPE_CODE);
          } catch (SQLException e) {
            throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
            		"Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
            		"Cause: " + e, e);
          }
        } else {
          //由于参数非空,走这个方法。setNonNullParameter是抽象方法,由子类实现
          setNonNullParameter(ps, i, parameter, jdbcType);
        }
      }
    

      

    这里的参数类型为int,对应的实现类为为IntegerTypeHandler

      @Override
      public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
          throws SQLException {
        ps.setInt(i, parameter);
      }  

    对应JDBC的处理为preparedStatement.setInt(index,value)

    经过上面的分析,最终处理还是JDBC那一套。通过connection创建preparedStatement;对preparedStatement进行参数封装;

    3) handler.<E>query(stmt, resultHandler);

      public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        return delegate.<E>query(statement, resultHandler);
      }
    
    //PreparedStatementHandler.query()
      public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        //1、执行execute操作
        ps.execute();
        //2、对结果进行封装
        return resultSetHandler.<E> handleResultSets(ps);
      }
    

      

    总结:mybatis操作流程如下

    1) 解析configuration.xml,生成Environment、Setting、Mapper等对象,并注册到Configuration

    2) 从SqlSessionFactory中获取SqlSession,SqlSession作为操作入口,接收用户的数据库操作,并委托给内部的Executor来实现

    3) Executor内部StatementHandler负责Statement的创建;PreparedStatement参数的注入;execute方法的执行
    4) execute方法执行,ResultSetHandler进行结果的封装

    参考:原生Mybatis框架源码解析

  • 相关阅读:
    ****阿里云使用+快速运维总结(不断更新)
    Linux 标准目录结构
    linux awk命令
    反射型 DDoS 攻击的原理和防范措施
    容器平台选型的十大模式:Docker、DC/OS、K8S 谁与当先?
    谈谈数据库的跨机房容灾-网易云
    前端 支持 超大上G,多附件上传
    java 支持 超大上G,多附件上传讨论
    java 支持 超大上G,多附件上传分享
    java 支持 超大上G,多附件上传功能
  • 原文地址:https://www.cnblogs.com/linlf03/p/12565333.html
Copyright © 2011-2022 走看看