MyBatis执行流程源码分析

什么是MyBatis?

MyBatis是一种持久化的ORM(Object Relational Mapping)框架。什么是ORM?用于实现面向对象编程语言中,不同系统的数据类型之间数据的转换。
就比如说,Java中有一个User类,MySQL中有一个user表,MyBatis就实现了User类和user表的映射(也就是Java实体类和user表对应,同时Java类中的每个属性和user表中的每一列对应)。

在这里插入图片描述
在这里插入图片描述
MyBatis还支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

MyBatis快速入门

运行mybatis源码项目
为了便于更好分析源码,我们这里直接下载了MyBatis-3的源码,直接在MyBatis源码工程编写demo调试。
下载完成后,解压后,然后IDEA打开。
gxMQ==,size_16,color_FFFFFF,t_70#pic_center)

接下来就是Maven导入jar包。maven导入完成后,然后我们这时候发现项目是不可运行的,因为没有设置编译后classes文件存放目录,点击File-Project Structure
在这里插入图片描述
设置Project compiler output
在这里插入图片描述
这时候mybatis源码文件就可以运行了。
编写简单入门案例
一般的普通项目都是会导入mybatis的jar包
在这里插入图片描述
但是我们这里是直接使用的mybatis源码,所有不需要导入mybatis的jar包。
然后我们在pom.xml文件导入mysql-connector的jar包的依赖

    <!--mysql -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.13</version>
    </dependency>

目录如下
在这里插入图片描述
注意:这里要修改以下java目录类型(改为Sources)和resoures目录类型(改为Resource),
打开Project Strucre - Modules,点击目录-mark as Sources/Tests/Resources/…
在这里插入图片描述

然后我们编写mybatis的配置文件mybatis-config.xml

<?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>
    <properties resource="jdbc.properties"/>
    <settings>
        <!--打开延迟加载的开关-->
        <setting name= "lazyLoadingEnabled" value= "true"/>
        <!--将积极加载改为按需加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!-- 可以阻挡不相干的操作触发,实现懒加载-->
        <setting name="lazyLoadTriggerMethods"  value=""/>
    </settings>
    <!--配置所有实体类的别名-->
    <typeAliases>
        <!--<typeAlias type="org.lieying.test.bean.User" alias="User"/>-->
        <!--自动扫描包下所有有@Alias注解的类-->
        <typeAlias alias="User" type="org.apache.demo.User"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <!-- type="JDBC" 代表使用JDBC的提交和回滚来管理事务 -->
            <transactionManager type="JDBC" />
            <!-- mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI -->
            <!-- POOLED 表示支持JDBC数据源连接池 -->
            <!-- UNPOOLED 表示不支持数据源连接池 -->
            <!-- JNDI 表示支持外部数据源连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

编写一个User类

package org.apache.demo;

public class User {
    
    

  private int id;
  private String name;

  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;
  }

  @Override
  public String toString() {
    
    
    return "User{" +
      "id=" + id +
      ", name='" + name + '\'' +
      '}';
  }
}

编写UserMapper.java文件

package org.apache.demo;

import org.apache.ibatis.annotations.Select;


public interface UserMapper {
    
    

    //@Select("select * from user where id = #{id}")
    User selectById(int id);
}

编写UserMapper.xml文件

<?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="org.apache.demo.UserMapper">
  <select id="selectById" resultType="User">
    select * from user where id = #{id}
  </select>
</mapper>

编写jdbc.properties文件

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testspring?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
jdbc.username=root
jdbc.password=200934652qwe

编写测试类

package org.apache.demo;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class TestMybatis {
    
    

  public static void main(String[] args) throws IOException {
    
    

    //把文件放入输入流中
    InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
    //构建SqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
    //获取一个SqlSession
    SqlSession sqlSession=sqlSessionFactory.openSession();
    //执行查询方法
    User user= sqlSession.selectOne("org.apache.demo.UserMapper.selectById",1);
    System.out.println(user);
//    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//    System.out.println(userMapper.selectById(1));
  }
}

然后运行测试类。
在这里插入图片描述

发现运行成功,即我们这里成功的使用了mybatis从MySQL数据库查询了id=1的user。

MyBatis执行流程

我们首先要获取数据源,这里的数据源我们配置在mybatis-config.xml文件中
现在前面配置了jdbc.properties中的driver、url、username、password
在这里插入图片描述
在这里插入图片描述
那么mybatis是如何解析的呢?
我们在测试类设置断点
在这里插入图片描述
进入到build方法
在这里插入图片描述

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    
    
    try {
    
    
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
    
    
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
    
    
      ErrorContext.instance().reset();
      try {
    
    
        inputStream.close();
      } catch (IOException e) {
    
    
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

然后通过parse.parse()方法解析,解析后返回一个Configuration对象,然后通过build()方法返回一个SqlSessionFactory对象。
我们看一下parse()方法

  public Configuration parse() {
    
    
    if (parsed) {
    
    
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));//解析mybatis-config.xml中的configuration标签,因此该方法就是解析mybatis-config.xml文件
    return configuration;
  }

进入parseConfiguration方法,我们发现这里又很多解析不同结点的方法,我们发现这里的结点名字和我们mybatis-config.xml文件的名字一致且顺序一致。
在这里插入图片描述

 private void parseConfiguration(XNode root) {
    
    
    try {
    
    
      // issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      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);
    }
  }

我们先看看我们配置的jdbc.properties是如何解析的,进入propertiesElement方法

  private void propertiesElement(XNode context) throws Exception {
    
    
    if (context != null) {
    
    //结点不为空,也就是properties标签存在
      Properties defaults = context.getChildrenAsProperties();//
      String resource = context.getStringAttribute("resource");//通过resource的方式设置的properties文件路径
      String url = context.getStringAttribute("url");//通过url的方式设置的properties文件路径
      if (resource != null && url != null) {
    
    //resources和url只能同时存在一种
        throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
      }
      if (resource != null) {
    
    //当配置的是resource的时候
        defaults.putAll(Resources.getResourceAsProperties(resource));//把resource配置的文件的内容,加到defaults中,获取文件所有的name-value,我们在propertis配置的就是driver=xxx的方式,此方法把这些name value就是map的形式,properties实现了hashtable接口,因此改方法就是把jdbc.properties文件在配置的每一项存在一个hasbtable里面
      } else if (url != null) {
    
    //当配置的是url的时候
        defaults.putAll(Resources.getUrlAsProperties(url));//通过urlf方式
      }
     //执行完以上操作,我们就完成了获取了propoerties标签配置的文件/url,并把所有内容加入到了defaults里面
      Properties vars = configuration.getVariables();
      if (vars != null) {
    
    
        defaults.putAll(vars);
      }

      parser.setVariables(defaults);//为解析器设置variables,这时候解析器就获得了这些properties文件在的这些与数据库连接相关的属性
      configuration.setVariables(defaults);//configuration设置variables
    }
  }

然后我们看environments标签的解析,environmentsElement方法

  private void environmentsElement(XNode context) throws Exception {
    
    
    if (context != null) {
    
    
      if (environment == null) {
    
    
        environment = context.getStringAttribute("default");//获取属性为default的environments标签
      }
      for (XNode child : context.getChildren()) {
    
    //遍历environments,即在这里解析不同环境下的配置的数据源
        String id = child.getStringAttribute("id");//获取environment的id
        if (isSpecifiedEnvironment(id)) {
    
    
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));//获取TransactionFactory类型根据transactionManager标签
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));//获取DataSourceFactory 类型根据dataSource标签
          DataSource dataSource = dsFactory.getDataSource();
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);//以当前事务管理器和数据源build一个environmentBuilder
          configuration.setEnvironment(environmentBuilder.build());//设置当前环境
        }
      }
    }
  }

然后parse就完成了,pase方法返回了一个Configuration对象

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

然后就通过build方法构建了一个SqlSessionFactory
在这里插入图片描述

然后我们在执行sqlSessionFactory的openSession方法,
进入openSession方法

  @Override
  public SqlSession openSession() {
    
    
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

进入openSessionFromDataSource方法

 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    
    
    Transaction tx = null;
    try {
    
    
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      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();
    }
  }

通过这种方法就获取到了一个SqlSession对象
在这里插入图片描述
然后我们执行selectOne方法获取id为1的用户

 User user= sqlSession.selectOne("org.apache.demo.UserMapper.selectById",1);

然后进入到DefaultSqlSession的selectOne方法,

  @Override
  public <T> T selectOne(String statement, Object parameter) {
    
    
    // Popular vote was to return null on 0 results and throw exception on too many.
    List<T> list = this.selectList(statement, parameter);//执行selectList方法
    if (list.size() == 1) {
    
    //如果查询行数为1
      return list.get(0);//返回查询到的记录
    } else if (list.size() > 1) {
    
    //如果查询行数大于1
      throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());//抛出异常
    } else {
    
    
      return null;
    }
  }

执行selectList方法后,我们发现控制台多了以下内容
在这里插入图片描述
因此,通过selectList方法,我们连接了数据库,并执行了select * from user where id=1这条sql语句。
这里我们重点看selectList方法。

  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    
    
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    
    
    try {
    
    
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
    
    
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
    
    
      ErrorContext.instance().reset();
    }
  }

进入CachingExecutor的query方法

  @Override
  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, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
    
    
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    return delegate.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) {
    
    //如果Executor已经关闭
      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();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
    
    
        // issue #482
        clearLocalCache();
      }
    }
    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 {
    
    
      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方法

  @Override
  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();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
    
    
      closeStatement(stmt);
    }
  }

进入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());
    }

  }

这里是Prepared,因此进入new一个PreparedStatementHandler对象,
进入PreparedStatementHandler的构造方法

  public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    
    
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

进入PreparedStatementHandler的父类BaseStatementHandler的构造方法

  protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    
    
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) {
    
     // issue #435, get the key before calculating the statement
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }
    this.boundSql = boundSql;

    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }

然后看下Configuration类的getTypeHandlerRegistry方法

  public TypeHandlerRegistry getTypeHandlerRegistry() {
    
    
    return typeHandlerRegistry;
  }

看下Configuration类的typeHandlerRegistry属性,发现该属性是一个final属性(不可变),默认new了一个TypeHandlerRegistry 对象,

  protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);

我们看一下它的构造方法

 public TypeHandlerRegistry(Configuration configuration) {
    
    
    this.unknownTypeHandler = new UnknownTypeHandler(configuration);

    register(Boolean.class, new BooleanTypeHandler());
    register(boolean.class, new BooleanTypeHandler());
    register(JdbcType.BOOLEAN, new BooleanTypeHandler());
    register(JdbcType.BIT, new BooleanTypeHandler());

    register(Byte.class, new ByteTypeHandler());
    register(byte.class, new ByteTypeHandler());
    register(JdbcType.TINYINT, new ByteTypeHandler());

    register(Short.class, new ShortTypeHandler());
    register(short.class, new ShortTypeHandler());
    register(JdbcType.SMALLINT, new ShortTypeHandler());

    register(Integer.class, new IntegerTypeHandler());
    register(int.class, new IntegerTypeHandler());
    register(JdbcType.INTEGER, new IntegerTypeHandler());

    register(Long.class, new LongTypeHandler());
    register(long.class, new LongTypeHandler());

    register(Float.class, new FloatTypeHandler());
    register(float.class, new FloatTypeHandler());
    register(JdbcType.FLOAT, new FloatTypeHandler());

    register(Double.class, new DoubleTypeHandler());
    register(double.class, new DoubleTypeHandler());
    register(JdbcType.DOUBLE, new DoubleTypeHandler());

    register(Reader.class, new ClobReaderTypeHandler());
    register(String.class, new StringTypeHandler());
    register(String.class, JdbcType.CHAR, new StringTypeHandler());
    register(String.class, JdbcType.CLOB, new ClobTypeHandler());
    register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
    register(String.class, JdbcType.LONGVARCHAR, new StringTypeHandler());
    register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
    register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
    register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
    register(JdbcType.CHAR, new StringTypeHandler());
    register(JdbcType.VARCHAR, new StringTypeHandler());
    register(JdbcType.CLOB, new ClobTypeHandler());
    register(JdbcType.LONGVARCHAR, new StringTypeHandler());
    register(JdbcType.NVARCHAR, new NStringTypeHandler());
    register(JdbcType.NCHAR, new NStringTypeHandler());
    register(JdbcType.NCLOB, new NClobTypeHandler());

    register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
    register(JdbcType.ARRAY, new ArrayTypeHandler());

    register(BigInteger.class, new BigIntegerTypeHandler());
    register(JdbcType.BIGINT, new LongTypeHandler());

    register(BigDecimal.class, new BigDecimalTypeHandler());
    register(JdbcType.REAL, new BigDecimalTypeHandler());
    register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
    register(JdbcType.NUMERIC, new BigDecimalTypeHandler());

    register(InputStream.class, new BlobInputStreamTypeHandler());
    register(Byte[].class, new ByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
    register(byte[].class, new ByteArrayTypeHandler());
    register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
    register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
    register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
    register(JdbcType.BLOB, new BlobTypeHandler());

    register(Object.class, unknownTypeHandler);
    register(Object.class, JdbcType.OTHER, unknownTypeHandler);
    register(JdbcType.OTHER, unknownTypeHandler);

    register(Date.class, new DateTypeHandler());
    register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
    register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
    register(JdbcType.TIMESTAMP, new DateTypeHandler());
    register(JdbcType.DATE, new DateOnlyTypeHandler());
    register(JdbcType.TIME, new TimeOnlyTypeHandler());

    register(java.sql.Date.class, new SqlDateTypeHandler());
    register(java.sql.Time.class, new SqlTimeTypeHandler());
    register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());

    register(String.class, JdbcType.SQLXML, new SqlxmlTypeHandler());

    register(Instant.class, new InstantTypeHandler());
    register(LocalDateTime.class, new LocalDateTimeTypeHandler());
    register(LocalDate.class, new LocalDateTypeHandler());
    register(LocalTime.class, new LocalTimeTypeHandler());
    register(OffsetDateTime.class, new OffsetDateTimeTypeHandler());
    register(OffsetTime.class, new OffsetTimeTypeHandler());
    register(ZonedDateTime.class, new ZonedDateTimeTypeHandler());
    register(Month.class, new MonthTypeHandler());
    register(Year.class, new YearTypeHandler());
    register(YearMonth.class, new YearMonthTypeHandler());
    register(JapaneseDate.class, new JapaneseDateTypeHandler());

    // issue #273
    register(Character.class, new CharacterTypeHandler());
    register(char.class, new CharacterTypeHandler());
  }

然后进入register方法


  public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler) {
    
    
    register((Type) javaType, typeHandler);
  }

  private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {
    
    
    MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
    if (mappedJdbcTypes != null) {
    
    
      for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
    
    
        register(javaType, handledJdbcType, typeHandler);
      }
      if (mappedJdbcTypes.includeNullJdbcType()) {
    
    
        register(javaType, null, typeHandler);
      }
    } else {
    
    
      register(javaType, null, typeHandler);
    }
  }

发现TypeHandlerRegistry构造方法就是做了java类/类型 到数据库字段 的映射(handler),也就是每个java类型注册一个handler,比如我们看一个BooleanTypeHandler方法

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

然后我们看见了我们常用的PreparedStatement类,进入setBoolean方法
在这里插入图片描述

这不就是我们常用的Preparedtatement方法吗。
执行完 this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();后就获得了typeHandlerRegistry
在这里插入图片描述
然后我们继续刚才的BaseStatementHandler方法

  protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    
    
   //获取mappedStatement、executor、rowBounds
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) {
    
     // issue #435, get the key before calculating the statement
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;

    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);//创建参数处理器
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);//创建结果集处理器
  }

然后我们就获得了一个StatementHandler,回到刚才的Configuration的newStatementHandler方法

  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();//获取configuration
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);//创建statementHandler

      stmt = prepareStatement(handler, ms.getStatementLog());//获取statement
      return handler.query(stmt, resultHandler);
    } finally {
    
    
      closeStatement(stmt);
    }
  }

我们看一下preparedStatement方法


  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    
    
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return stmt;
  }

然后看一下getConnection方法


  protected Connection getConnection(Log statementLog) throws SQLException {
    
    
    Connection connection = transaction.getConnection();
    if (statementLog.isDebugEnabled()) {
    
    
      return ConnectionLogger.newInstance(connection, statementLog, queryStack);
    } else {
    
    
      return connection;
    }
  }

我们发现控制台打印出JDBC连接成功的日志
在这里插入图片描述
然后我们查看getConnection()方法,该方法打印了日志在这里插入图片描述

  protected void openConnection() throws SQLException {
    
    
    if (log.isDebugEnabled()) {
    
    
      log.debug("Opening JDBC Connection");
    }
    connection = dataSource.getConnection();
    if (level != null) {
    
    
      connection.setTransactionIsolation(level.getLevel());
    }
    setDesiredAutoCommit(autoCommit);
  }

查看getConnection方法,

  @Override
  public Connection getConnection() throws SQLException {
    
    
    return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();//先执行popConnection获取一个PooledConnection,然后获取它的代理连接getProxyConnection
  }

查看popConnection方法,此方法 通过 conn = new PooledConnection(dataSource.getConnection(), this);获取连接,成功会打印日志在这里插入图片描述
PooledConnection的构造方法,

```java
  public PooledConnection(Connection connection, PooledDataSource dataSource) {
    
    
    this.hashCode = connection.hashCode();
    this.realConnection = connection;
    this.dataSource = dataSource;
    this.createdTimestamp = System.currentTimeMillis();
    this.lastUsedTimestamp = System.currentTimeMillis();
    this.valid = true;
    this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);//通过jdk动态代理的创建一个代理连接
  }

在这里插入图片描述


```java

  private PooledConnection popConnection(String username, String password) throws SQLException {
    boolean countedWait = false;
    PooledConnection conn = null;
    long t = System.currentTimeMillis();
    int localBadConnectionCount = 0;

    while (conn == null) {
      synchronized (state) {
        if (!state.idleConnections.isEmpty()) {
          // Pool has available connection
          conn = state.idleConnections.remove(0);
          if (log.isDebugEnabled()) {
            log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
          }
        } else {
          // Pool does not have available connection
          if (state.activeConnections.size() < poolMaximumActiveConnections) {
            // Can create new connection
            conn = new PooledConnection(dataSource.getConnection(), this);
            if (log.isDebugEnabled()) {//如果日志debug级别开启
              log.debug("Created connection " + conn.getRealHashCode() + ".");
            }//创建连接xxxxx
          } else {
            // Cannot create new connection
            PooledConnection oldestActiveConnection = state.activeConnections.get(0);
            long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
            if (longestCheckoutTime > poolMaximumCheckoutTime) {
              // Can claim overdue connection
              state.claimedOverdueConnectionCount++;
              state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
              state.accumulatedCheckoutTime += longestCheckoutTime;
              state.activeConnections.remove(oldestActiveConnection);
              if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
                try {
                  oldestActiveConnection.getRealConnection().rollback();
                } catch (SQLException e) {
                  /*
                     Just log a message for debug and continue to execute the following
                     statement like nothing happened.
                     Wrap the bad connection with a new PooledConnection, this will help
                     to not interrupt current executing thread and give current thread a
                     chance to join the next competition for another valid/good database
                     connection. At the end of this loop, bad {@link @conn} will be set as null.
                   */
                  log.debug("Bad connection. Could not roll back");
                }
              }
              conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
              conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());
              conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp());
              oldestActiveConnection.invalidate();
              if (log.isDebugEnabled()) {
                log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
              }
            } else {
              // Must wait
              try {
                if (!countedWait) {
                  state.hadToWaitCount++;
                  countedWait = true;
                }
                if (log.isDebugEnabled()) {
                  log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
                }
                long wt = System.currentTimeMillis();
                state.wait(poolTimeToWait);
                state.accumulatedWaitTime += System.currentTimeMillis() - wt;
              } catch (InterruptedException e) {
                break;
              }
            }
          }
        }
        if (conn != null) {
          // ping to server and check the connection is valid or not
          if (conn.isValid()) {
            if (!conn.getRealConnection().getAutoCommit()) {
              conn.getRealConnection().rollback();
            }
            conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
            conn.setCheckoutTimestamp(System.currentTimeMillis());
            conn.setLastUsedTimestamp(System.currentTimeMillis());
            state.activeConnections.add(conn);
            state.requestCount++;
            state.accumulatedRequestTime += System.currentTimeMillis() - t;
          } else {
            if (log.isDebugEnabled()) {
              log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection.");
            }
            state.badConnectionCount++;
            localBadConnectionCount++;
            conn = null;
            if (localBadConnectionCount > (poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance)) {
              if (log.isDebugEnabled()) {
                log.debug("PooledDataSource: Could not get a good connection to the database.");
              }
              throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
            }
          }
        }
      }

    }

    if (conn == null) {
      if (log.isDebugEnabled()) {
        log.debug("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
      }
      throw new SQLException("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
    }

    return conn;
  }

然后我们看一下dataSource.getConnection方法,

  @Override
  public Connection getConnection() throws SQLException {
    
    
    return doGetConnection(username, password);//传递用户名和密码
  }
  private Connection doGetConnection(String username, String password) throws SQLException {
    
    
    Properties props = new Properties();//创建一个Properties类,
    if (driverProperties != null) {
    
    
      props.putAll(driverProperties);
    }
    if (username != null) {
    
    //把用户名传进去
      props.setProperty("user", username);
    }
    if (password != null) {
    
    //把密码传进去
      props.setProperty("password", password);
    }
    return doGetConnection(props);
  }

进入doGetConnection方法

  private Connection doGetConnection(Properties properties) throws SQLException {
    
    
    initializeDriver();//初始化驱动
    Connection connection = DriverManager.getConnection(url, properties);
    configureConnection(connection);//调用DriverManager.getConnection方法获取连接
    return connection;
  }

这时候终于找到了我们使用jdbc连接数据库常用的DriverManager方法,
继续回到JdbcTransaction类的openConnection方法

  protected void openConnection() throws SQLException {
    
    
    if (log.isDebugEnabled()) {
    
    //日志的debug级别开启
      log.debug("Opening JDBC Connection");//打印  Opening JDBC Connection
    }
    connection = dataSource.getConnection();
    if (level != null) {
    
    //事务隔离级别不为空
      connection.setTransactionIsolation(level.getLevel());
    }
    setDesiredAutoCommit(autoCommit);//设置事务是否自动提交,openSession方法设置默认不会自动提交
  }

setDesiredAutoCommit方法(Connection类)

  protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
    
    
    try {
    
    
      if (connection.getAutoCommit() != desiredAutoCommit) {
    
    
        if (log.isDebugEnabled()) {
    
    
          log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");
        }
        connection.setAutoCommit(desiredAutoCommit);
      }
    } catch (SQLException e) {
    
    
      // Only a very poorly implemented driver would fail here,
      // and there's not much we can do about that.
      throw new TransactionException("Error configuring AutoCommit.  "
          + "Your driver may not support getAutoCommit() or setAutoCommit(). "
          + "Requested setting: " + desiredAutoCommit + ".  Cause: " + e, e);
    }
  }

回到JdbcTransaction的getConnection方法

  @Override
  public Connection getConnection() throws SQLException {
    
    
    if (connection == null) {
    
    
      openConnection();
    }
    return connection;
  }

回到BaseExecutor的getConnection方法

  protected Connection getConnection(Log statementLog) throws SQLException {
    
    
    Connection connection = transaction.getConnection();//获取连接
    if (statementLog.isDebugEnabled()) {
    
    //如果开启debug级别日志
      return ConnectionLogger.newInstance(connection, statementLog, queryStack);//使的该连接增加日志打印
    } else {
    
    
      return connection;
    }
  }
  public static Connection newInstance(Connection conn, Log statementLog, int queryStack) {
    
    //创建一个代理对象,为连接做日志功能,代理的目的就是增强,这里就是对连接过程中的操作进行日志打印
    InvocationHandler handler = new ConnectionLogger(conn, statementLog, queryStack);
    ClassLoader cl = Connection.class.getClassLoader();
    return (Connection) Proxy.newProxyInstance(cl, new Class[]{
    
    Connection.class}, handler);//jdk动态代理
  }

通过openConnection方法成功的获取了一个连接
回到preparedStatement方法(SimpleExecutor类)

  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    
    
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return stmt;
  }

进入RoutingStatementHandler的prepare方法

  @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    
    
    return delegate.prepare(connection, transactionTimeout);
  }

进入BaseStatementHandler的prepare方法

  @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    
    
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
    
    
      statement = instantiateStatement(connection);
      setStatementTimeout(statement, transactionTimeout);
      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);
    }
  }

回到SimpleHandler的prepareStatement方法

  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    
    
    Statement stmt;
    Connection connection = getConnection(statementLog);//获取连接
    stmt = handler.prepare(connection, transaction.getTimeout());//获取statement
    handler.parameterize(stmt);
    return stmt;
  }

进入parameterize方法(RoutingStatementHandler类)


  @Override
  public void parameterize(Statement statement) throws SQLException {
    
    
    delegate.parameterize(statement);
  }

进入parameterize方法(PreparedStatementHandler类)

  @Override
  public void parameterize(Statement statement) throws SQLException {
    
    
    parameterHandler.setParameters((PreparedStatement) statement);
  }

进入 DefaultParameterHandler的setParameters方法,为statement设置参数

 public void setParameters(PreparedStatement ps) {
    
    
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
    
    
      for (int i = 0; i < parameterMappings.size(); i++) {
    
    
        ParameterMapping parameterMapping = parameterMappings.get(i);
        if (parameterMapping.getMode() != ParameterMode.OUT) {
    
    
          Object value;
          String propertyName = parameterMapping.getProperty();
          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 {
    
    
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            value = metaObject.getValue(propertyName);
          }
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          JdbcType jdbcType = parameterMapping.getJdbcType();
          if (value == null && jdbcType == null) {
    
    
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
    
    
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
          } catch (TypeException | SQLException e) {
    
    
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          }
        }
      }
    }
  }

回到SimpleHandler的doQuery方法

  @Override
  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();//获取configuration
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);//创建statementHandler

      stmt = prepareStatement(handler, ms.getStatementLog());//获取statement
      return handler.query(stmt, resultHandler);
    } finally {
    
    
      closeStatement(stmt);
    }
  }

执行RoutingStatementHandler的query方法

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    
    
    return delegate.query(statement, resultHandler);
  }

执行PreparedStatementHandler的query方法

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    
    
    PreparedStatement ps = (PreparedStatement) statement;//获取statement方法
    ps.execute();//
    return resultSetHandler.handleResultSets(ps);
  }

然后进入execute方法,这时候我们F7调试发现进入的不是execute方法,是PreparedStatementLogger的invoke方法,因为PreparedStatementLogger实现了InvocationHandler,然后我们看一下invoke方法

 public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
    
    
    try {
    
    
      if (Object.class.equals(method.getDeclaringClass())) {
    
    
        return method.invoke(this, params);
      }
      if (EXECUTE_METHODS.contains(method.getName())) {
    
    //EXECUTE_METHODS包含execute方法
        if (isDebugEnabled()) {
    
    //设置debug日志级别
          debug("Parameters: " + getParameterValueString(), true);//打印参数
        }
        clearColumnInfo();//清除列信息
        if ("executeQuery".equals(method.getName())) {
    
    
          ResultSet rs = (ResultSet) method.invoke(statement, params);
          return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
        } else {
    
    
          return method.invoke(statement, params);//通过反射机制调用execute方法
        }
      } else if (SET_METHODS.contains(method.getName())) {
    
    
        if ("setNull".equals(method.getName())) {
    
    
          setColumn(params[0], null);
        } else {
    
    
          setColumn(params[0], params[1]);
        }
        return method.invoke(statement, params);
      } else if ("getResultSet".equals(method.getName())) {
    
    
        ResultSet rs = (ResultSet) method.invoke(statement, params);
        return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
      } else if ("getUpdateCount".equals(method.getName())) {
    
    
        int updateCount = (Integer) method.invoke(statement, params);
        if (updateCount != -1) {
    
    
          debug("   Updates: " + updateCount, false);
        }
        return updateCount;
      } else {
    
    
        return method.invoke(statement, params);
      }
    } catch (Throwable t) {
    
    
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

BaseJdbcLogger中

  protected void debug(String text, boolean input) {
    
    
    if (statementLog.isDebugEnabled()) {
    
    
      statementLog.debug(prefix(input) + text);
    }
  }

  static {
    
    
    SET_METHODS = Arrays.stream(PreparedStatement.class.getDeclaredMethods())
            .filter(method -> method.getName().startsWith("set"))
            .filter(method -> method.getParameterCount() > 1)
            .map(Method::getName)
            .collect(Collectors.toSet());

    EXECUTE_METHODS.add("execute");
    EXECUTE_METHODS.add("executeUpdate");
    EXECUTE_METHODS.add("executeQuery");
    EXECUTE_METHODS.add("addBatch");
  }

debug方法 StdOutImpl类中

  @Override
  public void debug(String s) {
    
    
    System.out.println(s);
  }

因此控制台打印了在这里插入图片描述
执行 method.invoke(statement, params)方法后,通过反射机制调用了execute方法(ClientPrepartedStatement,在mysql-connector的jar包中)

  public boolean execute() throws SQLException {
    
    
        try {
    
    
            synchronized(this.checkClosed().getConnectionMutex()) {
    
    
                JdbcConnection locallyScopedConn = this.connection;
                if (!this.doPingInstead && !this.checkReadOnlySafeStatement()) {
    
    
                    throw SQLError.createSQLException(Messages.getString("PreparedStatement.20") + Messages.getString("PreparedStatement.21"), "S1009", this.exceptionInterceptor);
                } else {
    
    
                    ResultSetInternalMethods rs = null;
                    this.lastQueryIsOnDupKeyUpdate = false;
                    if (this.retrieveGeneratedKeys) {
    
    
                        this.lastQueryIsOnDupKeyUpdate = this.containsOnDuplicateKeyUpdateInSQL();
                    }

                    this.batchedGeneratedKeys = null;
                    this.resetCancelledState();
                    this.implicitlyCloseAllOpenResults();
                    this.clearWarnings();
                    if (this.doPingInstead) {
    
    
                        this.doPingInstead();
                        return true;
                    } else {
    
    
                        this.setupStreamingTimeout(locallyScopedConn);
                        Message sendPacket = ((PreparedQuery)this.query).fillSendPacket();
                        String oldCatalog = null;
                        if (!locallyScopedConn.getCatalog().equals(this.getCurrentCatalog())) {
    
    
                            oldCatalog = locallyScopedConn.getCatalog();
                            locallyScopedConn.setCatalog(this.getCurrentCatalog());
                        }

                        CachedResultSetMetaData cachedMetadata = null;
                        boolean cacheResultSetMetadata = (Boolean)locallyScopedConn.getPropertySet().getBooleanProperty(PropertyKey.cacheResultSetMetadata).getValue();
                        if (cacheResultSetMetadata) {
    
    
                            cachedMetadata = locallyScopedConn.getCachedMetaData(((PreparedQuery)this.query).getOriginalSql());
                        }

                        locallyScopedConn.setSessionMaxRows(((PreparedQuery)this.query).getParseInfo().getFirstStmtChar() == 'S' ? this.maxRows : -1);
                        rs = this.executeInternal(this.maxRows, sendPacket, this.createStreamingResultSet(), ((PreparedQuery)this.query).getParseInfo().getFirstStmtChar() == 'S', cachedMetadata, false);
                        if (cachedMetadata != null) {
    
    
                            locallyScopedConn.initializeResultsMetadataFromCache(((PreparedQuery)this.query).getOriginalSql(), cachedMetadata, rs);
                        } else if (rs.hasRows() && cacheResultSetMetadata) {
    
    
                            locallyScopedConn.initializeResultsMetadataFromCache(((PreparedQuery)this.query).getOriginalSql(), (CachedResultSetMetaData)null, rs);
                        }

                        if (this.retrieveGeneratedKeys) {
    
    
                            rs.setFirstCharOfQuery(((PreparedQuery)this.query).getParseInfo().getFirstStmtChar());
                        }

                        if (oldCatalog != null) {
    
    
                            locallyScopedConn.setCatalog(oldCatalog);
                        }

                        if (rs != null) {
    
    
                            this.lastInsertId = rs.getUpdateID();
                            this.results = rs;
                        }

                        return rs != null && rs.hasRows();
                    }
                }
            }
        } catch (CJException var11) {
    
    
            throw SQLExceptionsMapping.translateException(var11, this.getExceptionInterceptor());
        }
    }

回到PreparedStatement的query方法,执行完execute方法后,就获得了resultsets
在这里插入图片描述

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    
    
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();//执行sql语句,得到resultsets
    return resultSetHandler.handleResultSets(ps);//处理结果集
  }

handleResultSets,(DefaultResultSetHandlerl)处理结果集

  //
  // HANDLE RESULT SETS
  //
  @Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    
    

    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    final List<Object> multipleResults = new ArrayList<>();

    int resultSetCount = 0;
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) {
    
    
      ResultMap resultMap = resultMaps.get(resultSetCount);
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
    
    
      while (rsw != null && resultSetCount < resultSets.length) {
    
    
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        if (parentMapping != null) {
    
    
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }

执行getFirstResultSet

  private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
    
    
    ResultSet rs = stmt.getResultSet();
    while (rs == null) {
    
    
      // move forward to get the first resultset in case the driver
      // doesn't return the resultset as the first result (HSQLDB 2.1)
      if (stmt.getMoreResults()) {
    
    
        rs = stmt.getResultSet();
      } else {
    
    
        if (stmt.getUpdateCount() == -1) {
    
    
          // no more results. Must be no resultset
          break;
        }
      }
    }
    return rs != null ? new ResultSetWrapper(rs, configuration) : null;
  }

执行getResultSet,这里也使用了反射机制

  @Override
  public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
    
    
    try {
    
    
      if (Object.class.equals(method.getDeclaringClass())) {
    
    
        return method.invoke(this, params);
      }
      if (EXECUTE_METHODS.contains(method.getName())) {
    
    
        if (isDebugEnabled()) {
    
    
          debug("Parameters: " + getParameterValueString(), true);
        }
        clearColumnInfo();
        if ("executeQuery".equals(method.getName())) {
    
    
          ResultSet rs = (ResultSet) method.invoke(statement, params);
          return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
        } else {
    
    
          return method.invoke(statement, params);
        }
      } else if (SET_METHODS.contains(method.getName())) {
    
    
        if ("setNull".equals(method.getName())) {
    
    
          setColumn(params[0], null);
        } else {
    
    
          setColumn(params[0], params[1]);
        }
        return method.invoke(statement, params);
      } else if ("getResultSet".equals(method.getName())) {
    
    //方法名称为getResultSet
        ResultSet rs = (ResultSet) method.invoke(statement, params);
        return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
      } else if ("getUpdateCount".equals(method.getName())) {
    
    
        int updateCount = (Integer) method.invoke(statement, params);
        if (updateCount != -1) {
    
    
          debug("   Updates: " + updateCount, false);
        }
        return updateCount;
      } else {
    
    
        return method.invoke(statement, params);
      }
    } catch (Throwable t) {
    
    
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

通过反射执行StatementImpl类(mysql-connector jar包) 的getResultSet方法


    public ResultSet getResultSet() throws SQLException {
    
    
        try {
    
    
            synchronized(this.checkClosed().getConnectionMutex()) {
    
    
                return this.results != null && this.results.hasRows() ? this.results : null;
            }
        } catch (CJException var5) {
    
    
            throw SQLExceptionsMapping.translateException(var5, this.getExceptionInterceptor());
        }
    }

执行完getResultSet方法后返回invoke方法

      else if ("getResultSet".equals(method.getName())) {
        ResultSet rs = (ResultSet) method.invoke(statement, params);
        return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);

ResultSetLogger.newInstance方法


  public static ResultSet newInstance(ResultSet rs, Log statementLog, int queryStack) {
    
    
    InvocationHandler handler = new ResultSetLogger(rs, statementLog, queryStack);
    ClassLoader cl = ResultSet.class.getClassLoader();
    return (ResultSet) Proxy.newProxyInstance(cl, new Class[]{
    
    ResultSet.class}, handler);
  }

后面还有好多就是结果集的处理,打印出以下日志

在这里插入图片描述

然后处理完后关闭statement(也是通过反射调用相应方法),这里就不一一写了,调用太多了,快晕了,这仅仅是一个查询
然后在一层一层的返回,最终返回到selectList方法

  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    
    
    try {
    
    
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
    
    
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
    
    
      ErrorContext.instance().reset();//清空排错信息
    }
  }

最终返回到selectOne方法,

  @Override
  public <T> T selectOne(String statement, Object parameter) {
    
    
    // Popular vote was to return null on 0 results and throw exception on too many.
    List<T> list = this.selectList(statement, parameter);//执行selectList方法
    if (list.size() == 1) {
    
    //如果查询行数为1
      return list.get(0);//返回查询到的记录
    } else if (list.size() > 1) {
    
    //如果查询行数大于1
      throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), " +
        "but found: " + list.size());//抛出异常
    } else {
    
    
      return null;
    }
  }
  User user= sqlSession.selectOne("org.apache.demo.UserMapper.selectById",1);

以上就是mybatis执行sql语句的调用过程。

我们顺便看一下jdbc是如何获取一个连接的吧
DriverManager.getConnection方法

    @CallerSensitive
    public static Connection getConnection(String url,
        java.util.Properties info) throws SQLException {
    
    

        return (getConnection(url, info, Reflection.getCallerClass()));
    }

进入getConnection(url, info, Reflection.getCallerClass()))

    private static Connection getConnection(
        String url, java.util.Properties info, Class<?> caller) throws SQLException {
    
    
        /*
         * When callerCl is null, we should check the application's
         * (which is invoking this class indirectly)
         * classloader, so that the JDBC driver class outside rt.jar
         * can be loaded from here.
         */
        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
        synchronized(DriverManager.class) {
    
    
            // synchronize loading of the correct classloader.
            if (callerCL == null) {
    
    
                callerCL = Thread.currentThread().getContextClassLoader();
            }
        }

        if(url == null) {
    
    
            throw new SQLException("The url cannot be null", "08001");
        }

        println("DriverManager.getConnection(\"" + url + "\")");

        // Walk through the loaded registeredDrivers attempting to make a connection.
        // Remember the first exception that gets raised so we can reraise it.
        SQLException reason = null;

        for(DriverInfo aDriver : registeredDrivers) {
    
    
            // If the caller does not have permission to load the driver then
            // skip it.
            if(isDriverAllowed(aDriver.driver, callerCL)) {
    
    
                try {
    
    
                    println("    trying " + aDriver.driver.getClass().getName());
                    Connection con = aDriver.driver.connect(url, info);
                    if (con != null) {
    
    
                        // Success!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);
                    }
                } catch (SQLException ex) {
    
    
                    if (reason == null) {
    
    
                        reason = ex;
                    }
                }

            } else {
    
    
                println("    skipping: " + aDriver.getClass().getName());
            }

        }

        // if we got here nobody could connect.
        if (reason != null)    {
    
    
            println("getConnection failed: " + reason);
            throw reason;
        }

        println("getConnection: no suitable driver found for "+ url);
        throw new SQLException("No suitable driver found for "+ url, "08001");
    }

查看connect方法

    public Connection connect(String var1, Properties var2) throws SQLException {
    
    
        if (var1.regionMatches(true, 0, "jdbc:default:connection", 0, "jdbc:default:connection".length())) {
    
    
            JDBCConnection var3 = (JDBCConnection)this.threadConnection.get();
            return var3 == null ? null : var3;
        } else {
    
    
            return getConnection(var1, var2);
        }
    }

initializeDriver方法

private synchronized void initializeDriver() throws SQLException {
    
    
    if (!registeredDrivers.containsKey(driver)) {
    
    
      Class<?> driverType;
      try {
    
    
        if (driverClassLoader != null) {
    
    
          driverType = Class.forName(driver, true, driverClassLoader);
        } else {
    
    
          driverType = Resources.classForName(driver);
        }
        // DriverManager requires the driver to be loaded via the system ClassLoader.
        // http://www.kfu.com/~nsayer/Java/dyn-jdbc.html
        Driver driverInstance = (Driver) driverType.getDeclaredConstructor().newInstance();
        DriverManager.registerDriver(new DriverProxy(driverInstance));
        registeredDrivers.put(driver, driverInstance);
      } catch (Exception e) {
    
    
        throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
      }
    }
  }

这时候成功获取到driver
在这里插入图片描述
进入connect方法(NonRegisteringDriver类中)

 public Connection connect(String url, Properties info) throws SQLException {
    
    
        try {
    
    
            try {
    
    
                if (!ConnectionUrl.acceptsUrl(url)) {
    
    //校验url的合法性
                    return null;
                } else {
    
    
                    ConnectionUrl conStr = ConnectionUrl.getConnectionUrlInstance(url, info);
                    switch(conStr.getType()) {
    
    //ConnectionUrl 类型
                    case SINGLE_CONNECTION://单个连接
                        return ConnectionImpl.getInstance(conStr.getMainHost());
                    case LOADBALANCE_CONNECTION://负载均衡连接
                        return LoadBalancedConnectionProxy.createProxyInstance((LoadbalanceConnectionUrl)conStr);
                    case FAILOVER_CONNECTION://故障连接
                        return FailoverConnectionProxy.createProxyInstance(conStr);
                    case REPLICATION_CONNECTION://拷贝连接
                        return ReplicationConnectionProxy.createProxyInstance((ReplicationConnectionUrl)conStr);
                    default:
                        return null;
                    }
                }
            } catch (UnsupportedConnectionStringException var5) {
    
    
                return null;
            } catch (CJException var6) {
    
    
                throw (UnableToConnectException)ExceptionFactory.createException(UnableToConnectException.class, Messages.getString("NonRegisteringDriver.17", new Object[]{
    
    var6.toString()}), var6);
            }
        } catch (CJException var7) {
    
    
            throw SQLExceptionsMapping.translateException(var7);
        }
    }

我们这里这是简单的单个连接,所以进入getInstance方法

    public static JdbcConnection getInstance(HostInfo hostInfo) throws SQLException {
    
    
        return new ConnectionImpl(hostInfo);
    }

ConnectionImpl构造方法


    public ConnectionImpl(HostInfo hostInfo) throws SQLException {
    
    
        try {
    
    
        //下面就是一些设置连接的主机、目的主机、端口、用户名、密码、数据库等信息
            this.origHostInfo = hostInfo;
            this.origHostToConnectTo = hostInfo.getHost();
            this.origPortToConnectTo = hostInfo.getPort();
            this.database = hostInfo.getDatabase();
            this.user = StringUtils.isNullOrEmpty(hostInfo.getUser()) ? "" : hostInfo.getUser();
            this.password = StringUtils.isNullOrEmpty(hostInfo.getPassword()) ? "" : hostInfo.getPassword();
            this.props = hostInfo.exposeAsProperties();
            this.propertySet = new JdbcPropertySetImpl();
            this.propertySet.initializeProperties(this.props);
            this.nullStatementResultSetFactory = new ResultSetFactory(this, (StatementImpl)null);
            this.session = new NativeSession(hostInfo, this.propertySet);
            this.session.addListener(this);
            this.autoReconnectForPools = this.propertySet.getBooleanProperty(PropertyKey.autoReconnectForPools);
            this.cachePrepStmts = this.propertySet.getBooleanProperty(PropertyKey.cachePrepStmts);
            this.autoReconnect = this.propertySet.getBooleanProperty(PropertyKey.autoReconnect);
            this.useUsageAdvisor = this.propertySet.getBooleanProperty(PropertyKey.useUsageAdvisor);
            this.reconnectAtTxEnd = this.propertySet.getBooleanProperty(PropertyKey.reconnectAtTxEnd);
            this.emulateUnsupportedPstmts = this.propertySet.getBooleanProperty(PropertyKey.emulateUnsupportedPstmts);
            this.ignoreNonTxTables = this.propertySet.getBooleanProperty(PropertyKey.ignoreNonTxTables);
            this.pedantic = this.propertySet.getBooleanProperty(PropertyKey.pedantic);
            this.prepStmtCacheSqlLimit = this.propertySet.getIntegerProperty(PropertyKey.prepStmtCacheSqlLimit);
            this.useLocalSessionState = this.propertySet.getBooleanProperty(PropertyKey.useLocalSessionState);
            this.useServerPrepStmts = this.propertySet.getBooleanProperty(PropertyKey.useServerPrepStmts);
            this.processEscapeCodesForPrepStmts = this.propertySet.getBooleanProperty(PropertyKey.processEscapeCodesForPrepStmts);
            this.useLocalTransactionState = this.propertySet.getBooleanProperty(PropertyKey.useLocalTransactionState);
            this.disconnectOnExpiredPasswords = this.propertySet.getBooleanProperty(PropertyKey.disconnectOnExpiredPasswords);
            this.readOnlyPropagatesToServer = this.propertySet.getBooleanProperty(PropertyKey.readOnlyPropagatesToServer);
            String exceptionInterceptorClasses = this.propertySet.getStringProperty(PropertyKey.exceptionInterceptors).getStringValue();
            if (exceptionInterceptorClasses != null && !"".equals(exceptionInterceptorClasses)) {
    
    
                this.exceptionInterceptor = new ExceptionInterceptorChain(exceptionInterceptorClasses, this.props, this.session.getLog());
            }

            if ((Boolean)this.cachePrepStmts.getValue()) {
    
    
                this.createPreparedStatementCaches();
            }

            if ((Boolean)this.propertySet.getBooleanProperty(PropertyKey.cacheCallableStmts).getValue()) {
    
    
                this.parsedCallableStatementCache = new LRUCache((Integer)this.propertySet.getIntegerProperty(PropertyKey.callableStmtCacheSize).getValue());
            }

            if ((Boolean)this.propertySet.getBooleanProperty(PropertyKey.allowMultiQueries).getValue()) {
    
    
                this.propertySet.getProperty(PropertyKey.cacheResultSetMetadata).setValue(false);
            }

            if ((Boolean)this.propertySet.getBooleanProperty(PropertyKey.cacheResultSetMetadata).getValue()) {
    
    
                this.resultSetMetadataCache = new LRUCache((Integer)this.propertySet.getIntegerProperty(PropertyKey.metadataCacheSize).getValue());
            }

            if (this.propertySet.getStringProperty(PropertyKey.socksProxyHost).getStringValue() != null) {
    
    
                this.propertySet.getProperty(PropertyKey.socketFactory).setValue(SocksProxySocketFactory.class.getName());
            }

            this.pointOfOrigin = (Boolean)this.useUsageAdvisor.getValue() ? LogUtils.findCallingClassAndMethod(new Throwable()) : "";
            this.dbmd = this.getMetaData(false, false);
            this.initializeSafeQueryInterceptors();
        } catch (CJException var5) {
    
    
            throw SQLExceptionsMapping.translateException(var5, this.getExceptionInterceptor());
        }

        try {
    
    
            this.createNewIO(false);
            this.unSafeQueryInterceptors();
            NonRegisteringDriver.trackConnection(this);
        } catch (SQLException var3) {
    
    
            this.cleanup(var3);
            throw var3;
        } catch (Exception var4) {
    
    
            this.cleanup(var4);
            throw SQLError.createSQLException((Boolean)this.propertySet.getBooleanProperty(PropertyKey.paranoid).getValue() ? Messages.getString("Connection.0") : Messages.getString("Connection.1", new Object[]{
    
    this.session.getHostInfo().getHost(), this.session.getHostInfo().getPort()}), "08S01", var4, this.getExceptionInterceptor());
        }
    }

createNewIO方法

 public void createNewIO(boolean isForReconnect) {
    
    
        try {
    
    
            synchronized(this.getConnectionMutex()) {
    
    //
                try {
    
    
                    if (!(Boolean)this.autoReconnect.getValue()) {
    
    
                        this.connectOneTryOnly(isForReconnect);
                        return;
                    }

                    this.connectWithRetries(isForReconnect);
                } catch (SQLException var6) {
    
    
                    throw (UnableToConnectException)ExceptionFactory.createException(UnableToConnectException.class, var6.getMessage(), var6);
                }

            }
        } catch (CJException var8) {
    
    
            throw SQLExceptionsMapping.translateException(var8, this.getExceptionInterceptor());
        }
    }

connectOneTryOnly方法

 private void connectOneTryOnly(boolean isForReconnect) throws SQLException {
    
    
        Object var2 = null;

        try {
    
    
            JdbcConnection c = this.getProxy();//获取代理对象
            this.session.connect(this.origHostInfo, this.user, this.password, this.database, DriverManager.getLoginTimeout() * 1000, c);
            boolean oldAutoCommit = this.getAutoCommit();
            int oldIsolationLevel = this.isolationLevel;
            boolean oldReadOnly = this.isReadOnly(false);
            String oldCatalog = this.getCatalog();
            this.session.setQueryInterceptors(this.queryInterceptors);
            this.initializePropsFromServer();
            if (isForReconnect) {
    
    
                this.setAutoCommit(oldAutoCommit);
                this.setTransactionIsolation(oldIsolationLevel);
                this.setCatalog(oldCatalog);
                this.setReadOnly(oldReadOnly);
            }

        } catch (UnableToConnectException var8) {
    
    
            this.close();
            this.session.getProtocol().getSocketConnection().forceClose();
            throw var8;
        } catch (Exception var9) {
    
    
            if (!(var9 instanceof PasswordExpiredException) && (!(var9 instanceof SQLException) || ((SQLException)var9).getErrorCode() != 1820) || (Boolean)this.disconnectOnExpiredPasswords.getValue()) {
    
    
                if (this.session != null) {
    
    
                    this.session.forceClose();
                }

                if (var9 instanceof SQLException) {
    
    
                    throw (SQLException)var9;
                } else if (var9.getCause() != null && var9.getCause() instanceof SQLException) {
    
    
                    throw (SQLException)var9.getCause();
                } else if (var9 instanceof CJException) {
    
    
                    throw (CJException)var9;
                } else {
    
    
                    SQLException chainedEx = SQLError.createSQLException(Messages.getString("Connection.UnableToConnect"), "08001", this.getExceptionInterceptor());
                    chainedEx.initCause(var9);
                    throw chainedEx;
                }
            }
        }
    }

this.session.connect方法(NativeSession类)

  public void connect(HostInfo hi, String user, String password, String database, int loginTimeout, TransactionEventHandler transactionManager) throws IOException {
    
    
        this.hostInfo = hi;
        this.setSessionMaxRows(-1);
        SocketConnection socketConnection = new NativeSocketConnection();//创建SockedConnection对象
        socketConnection.connect(this.hostInfo.getHost(), this.hostInfo.getPort(), this.propertySet, this.getExceptionInterceptor(), this.log, loginTimeout);//连接
        if (this.protocol == null) {
    
    
            this.protocol = NativeProtocol.getInstance(this, socketConnection, this.propertySet, this.log, transactionManager);
        } else {
    
    
            this.protocol.init(this, socketConnection, this.propertySet, transactionManager);
        }

        this.protocol.connect(user, password, database);
        this.protocol.getServerSession().setErrorMessageEncoding(this.protocol.getAuthenticationProvider().getEncodingForHandshake());
        this.isClosed = false;
    }

socketConnection.connect方法,该方法的作用是当前主机与mysql数据库服务器建立socket连接

  public void connect(String hostName, int portNumber, PropertySet propSet, ExceptionInterceptor excInterceptor, Log log, int loginTimeout) {
    
    
        try {
    
    
            this.port = portNumber;//端口号
            this.host = hostName;//主机
            this.propertySet = propSet;
            this.exceptionInterceptor = excInterceptor;
            this.socketFactory = this.createSocketFactory(propSet.getStringProperty(PropertyKey.socketFactory).getStringValue());//创建socketFactory
            this.mysqlSocket = (Socket)this.socketFactory.connect(this.host, this.port, propSet, loginTimeout);//创建mysqlSocket
            int socketTimeout = (Integer)propSet.getIntegerProperty(PropertyKey.socketTimeout).getValue();
            if (socketTimeout != 0) {
    
    
                try {
    
    
                    this.mysqlSocket.setSoTimeout(socketTimeout);
                } catch (Exception var9) {
    
    
                }
            }

            this.socketFactory.beforeHandshake();//握手之前
            Object rawInputStream;
            if ((Boolean)propSet.getBooleanProperty(PropertyKey.useReadAheadInput).getValue()) {
    
    
                rawInputStream = new ReadAheadInputStream(this.mysqlSocket.getInputStream(), 16384, (Boolean)propSet.getBooleanProperty(PropertyKey.traceProtocol).getValue(), log);
            } else if ((Boolean)propSet.getBooleanProperty(PropertyKey.useUnbufferedInput).getValue()) {
    
    
                rawInputStream = this.mysqlSocket.getInputStream();
            } else {
    
    
                rawInputStream = new BufferedInputStream(this.mysqlSocket.getInputStream(), 16384);
            }

            this.mysqlInput = new FullReadInputStream((InputStream)rawInputStream);//设置输入流
            this.mysqlOutput = new BufferedOutputStream(this.mysqlSocket.getOutputStream(), 16384);//设置输出流,即允许练级mysql所在主机的最大连接数为16384
        } catch (IOException var10) {
    
    
            throw ExceptionFactory.createCommunicationsException(propSet, (ServerSession)null, new PacketSentTimeHolder() {
    
    
            }, (PacketReceivedTimeHolder)null, var10, this.getExceptionInterceptor());
        }
    }

beforeHandshake方法

    public void beforeHandshake() throws IOException {
    
    
        this.resetLoginTimeCountdown();//重置登录时间计时
        this.socketTimeoutBackup = this.rawSocket.getSoTimeout();//备份
        this.rawSocket.setSoTimeout(this.getRealTimeout(this.socketTimeoutBackup));//设置连接的超时时间
    }

以上就是DriverManger.getConnection建立连接的全过程

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/rj2017211811/article/details/109380326