Mybatis工作原理

Mybatis的整体架构

在这里插入图片描述

源码包目录对应的架构图

在这里插入图片描述

核心学习的几部分:

1,MyBatis核心配置文件

Configuration

通过核心配置文件,我们对MyBatis进行配置,其中包括连接池管理,事物管理,缓存管理,映射文件配置.

配置文件的节点挺多的,都不知道什么意思,能不能换其他的属性值,他们的优点在哪儿?他们在什么情况下使用?它们各自的区别?带着这些个问题于是我就写了这篇博客。

public class Configuration {
	
	//环境变量
    protected Environment environment;
    
    //允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为false
    protected boolean safeRowBoundsEnabled;
    protected boolean safeResultHandlerEnabled;
	
	//是否开启自动驼峰命名规则(camel case)映射,
	//即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。
    protected boolean mapUnderscoreToCamelCase;
    
    //是否全属性的延迟加载
    protected boolean aggressiveLazyLoading;
    //是否允许单一语句返回多结果集(需要兼容驱动)
    protected boolean multipleResultSetsEnabled;
    
    //允许 JDBC 支持自动生成主键,需要驱动兼容。 true 使用主键自增
    protected boolean useGeneratedKeys;
    
    //使用列标签代替列名。不同的驱动在这方面会有不同的表现
    protected boolean useColumnLabel;
    
    //所有映射器的缓存开关 默认开启
    protected boolean cacheEnabled;
    
    protected boolean callSettersOnNulls;
    
    protected boolean useActualParamName;
    
    protected boolean returnInstanceForEmptyRow;
    
    protected String logPrefix;
    
    //日志的实现 未指定自动查找
    protected Class<? extends Log> logImpl;
    
    protected Class<? extends VFS> vfsImpl;
    
    //MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 
    //默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。
    // 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。
    protected LocalCacheScope localCacheScope;
  
    //当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。
    protected JdbcType jdbcTypeForNull;
  
 	 //指定哪个对象的方法触发一次延迟加载。
    protected Set<String> lazyLoadTriggerMethods;
    
    //设置超时时间,它决定驱动等待数据库响应的秒数。
    protected Integer defaultStatementTimeout;
    
	//为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖
    protected Integer defaultFetchSize;
    
    //配置默认的执行器。
    //SIMPLE 就是普通的执行器;
    //REUSE 执行器会重用预处理语句(prepared statements); 
    //BATCH 执行器将重用语句并执行批量更新。
    protected ExecutorType defaultExecutorType;
    
    //指定 MyBatis 应如何自动映射列到字段或属性。
    // NONE 表示取消自动映射;
    //PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。
    // FULL 会自动映射任意复杂的结果集(无论是否嵌套)。
    protected AutoMappingBehavior autoMappingBehavior;
    protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior;
    protected Properties variables;
    protected ReflectorFactory reflectorFactory;
    
    //对象工厂
    protected ObjectFactory objectFactory;

	//对象包装工厂
    protected ObjectWrapperFactory objectWrapperFactory;
   
    //延迟加载的全局开关 默认false
    protected boolean lazyLoadingEnabled;
   
    protected ProxyFactory proxyFactory;
   
    protected String databaseId;
   
    protected Class<?> configurationFactory;
   
    //注册所有mapper
    protected final MapperRegistry mapperRegistry;
   
    //拦截器执行链
    protected final InterceptorChain interceptorChain;
   
    //注册typeHandler 
    //无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,
    //还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
    //提示 从 3.4.5 开始,MyBatis 默认支持 JSR-310(日期和时间 API) 。
    protected final TypeHandlerRegistry typeHandlerRegistry;
   
    //注册类型及别名
    protected final TypeAliasRegistry typeAliasRegistry;
    protected final LanguageDriverRegistry languageRegistry;
    protected final Map<String, MappedStatement> mappedStatements;
    protected final Map<String, Cache> caches;
    protected final Map<String, ResultMap> resultMaps;
    protected final Map<String, ParameterMap> parameterMaps;
    protected final Map<String, KeyGenerator> keyGenerators;
    protected final Set<String> loadedResources;
    protected final Map<String, XNode> sqlFragments;
    protected final Collection<XMLStatementBuilder> incompleteStatements;
    protected final Collection<CacheRefResolver> incompleteCacheRefs;
    protected final Collection<ResultMapResolver> incompleteResultMaps;
    protected final Collection<MethodResolver> incompleteMethods;
    protected final Map<String, String> cacheRefMap;

    public Configuration(Environment environment) {
        this();
        this.environment = environment;
    }

    public Configuration() {
        this.safeResultHandlerEnabled = true;
        this.multipleResultSetsEnabled = true;
        this.useColumnLabel = true;
        this.cacheEnabled = true;
        this.useActualParamName = true;
        this.localCacheScope = LocalCacheScope.SESSION;
        this.jdbcTypeForNull = JdbcType.OTHER;
        this.lazyLoadTriggerMethods = new HashSet(Arrays.asList("equals", "clone", "hashCode", "toString"));
        this.defaultExecutorType = ExecutorType.SIMPLE;
        this.autoMappingBehavior = AutoMappingBehavior.PARTIAL;
        this.autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
        this.variables = new Properties();
        this.reflectorFactory = new DefaultReflectorFactory();
        this.objectFactory = new DefaultObjectFactory();
        this.objectWrapperFactory = new DefaultObjectWrapperFactory();
        this.lazyLoadingEnabled = false;
        this.proxyFactory = new JavassistProxyFactory();
        this.mapperRegistry = new MapperRegistry(this);
        this.interceptorChain = new InterceptorChain();
        this.typeHandlerRegistry = new TypeHandlerRegistry();
        this.typeAliasRegistry = new TypeAliasRegistry();
        this.languageRegistry = new LanguageDriverRegistry();
        this.mappedStatements = new Configuration.StrictMap("Mapped Statements collection");
        this.caches = new Configuration.StrictMap("Caches collection");
        this.resultMaps = new Configuration.StrictMap("Result Maps collection");
        this.parameterMaps = new Configuration.StrictMap("Parameter Maps collection");
        this.keyGenerators = new Configuration.StrictMap("Key Generators collection");
        this.loadedResources = new HashSet();
        this.sqlFragments = new Configuration.StrictMap("XML fragments parsed from previous mappers");
        this.incompleteStatements = new LinkedList();
        this.incompleteCacheRefs = new LinkedList();
        this.incompleteResultMaps = new LinkedList();
        this.incompleteMethods = new LinkedList();
        this.cacheRefMap = new HashMap();
        this.typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
        this.typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
        this.typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
        this.typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
        this.typeAliasRegistry.registerAlias("LRU", LruCache.class);
        this.typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
        this.typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
        this.typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
        this.typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
        this.typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
        this.typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
        this.typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
        this.typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
        this.typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
        this.typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
        this.typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
        this.typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
        this.typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
        this.typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
        this.languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
        this.languageRegistry.register(RawLanguageDriver.class);
    }
    }

Configruation里的重要方法

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        executorType = executorType == null ? this.defaultExecutorType : executorType;
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
        Object executor;
        if (ExecutorType.BATCH == executorType) {
            executor = new BatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {
            executor = new ReuseExecutor(this, transaction);
        } else {
            executor = new SimpleExecutor(this, transaction);
        }

        if (this.cacheEnabled) {
            executor = new CachingExecutor((Executor)executor);
        }
		//这个plginAll
        Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
        return executor;
    }

如果开启的缓存 则用缓存保装

2.Mapper映射文件

通过mapper映射文件,我们可以配置的mapper从而映射jdbc操作,其中映射包含insert ,delte,update, select,

parameterType参数类型, resultType结果类型, selectKey主键配置等等.

3.MyBatis的执行流程:

在不适用Spring的情况下使用Mybatis

//1.获取配置文件流
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//2.根据输入流构建工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.开启session
SqlSession session = sqlSessionFactory.openSession();
try {
// 调用方法
  Blog blog = session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
//关闭流
  session.close();
}

整的一个执行的流程图
在这里插入图片描述

最重要的信息 Configruation 对象全局唯一
Mybatis中所有配置项

核心层

1.配置文件解析

mapper-config.xml 该配置在xmlConfigBuilder解析
Mybatis使用Dom解析
mapper.xml 在xmlMapperBuilder中完成解析
对statement的解析委托给xmlStatementBuilder
涉及到PreparedMapping、ResultMapping、LanguageDriver、Discriminator、缓存、自动映射等一系列对象的构造,这里暂时略过,后面专题分析。

2.获取Mapper对象

在mybatis中,我们可以像下面这样通过声明对应的接口来绑定XML中的mapper,这样可以让我们尽早的发现XML的错误。

通过sqlsession的getMapper方法获取到mapper对象

一,mapper接口并未定义实现类,为什么mybatis可以获取到对应的对象?

二,mapper是如何执行对应的SQL的?

来看看session.getMapper()到底做了什么。它是从configuration中获取到对应的mapper对象,而configuration又是从mapperRegistry中获取,因此我们直接看mapperregistry中的方法:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//knownMapper是一个Map对象,保存了Mapper类型和对应的MapperProxyFactory。
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    //如果mapper中没有
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
    //工厂方法新建一个
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

在configruation中添加mapper

public <T> void addMapper(Class<T> type) {
   //接口类型
    if (type.isInterface()) {
      //类型是mapper
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      //是否加载完成
      boolean loadCompleted = false;
      try {
      	//类型和工厂放入mapper
        knownMappers.put(type, new MapperProxyFactory<T>(type));
        // It's important that the type is added before the parser is run
        // otherwise the binding may automatically be attempted by the
        // mapper parser. If the type is already known, it won't try.
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        parser.parse();
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
        //如果没有加载完成 则移除
          knownMappers.remove(type);
        }
      }
    }
  }

回到getMapper中,我们可以看到真正获取mapper实例是交给代理工厂的newInstance方法处理的,来看下MapperProxyFactory类:

public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    //我们得到的mapper对象是由JDK动态代理创建
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    //创建代理对象 接口 方法缓存
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

大概知道mapper对象是由JDK动态代理所创建的,而mapperInterface就是我们需要代理的接口

Mapper代理对象

public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  //sqlSession对象
  private final SqlSession sqlSession;
  //代理的接口
  private final Class<T> mapperInterface;
  //方法的缓存
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        //如果是Object中声明的方法,那么直接invoke
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      //如果是默认的方法
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    //对应mapper中的方法,委托给mapperMethod执行
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    //缓存mappermethod
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

  @UsesJava7
  private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
      throws Throwable {
    final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
        .getDeclaredConstructor(Class.class, int.class);
    if (!constructor.isAccessible()) {
      constructor.setAccessible(true);
    }
    final Class<?> declaringClass = method.getDeclaringClass();
    return constructor
        .newInstance(declaringClass,
            MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
                | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
        .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
  }

  /**
   * Backport of java.lang.reflect.Method#isDefault()
   */
  private boolean isDefaultMethod(Method method) {
    //判断方法类型
    return (method.getModifiers()
        & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
        && method.getDeclaringClass().isInterface();
  }
}

Mapper的方法委托给mappermethod执行

MapperMethhod如下

public class MapperMethod {
//sql命令行
  private final SqlCommand command;
 //方法签名
  private final MethodSignature method;

  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    //根据config mapper和method判断方法类型
    this.command = new SqlCommand(config, mapperInterface, method);
    //解析返回类型
    this.method = new MethodSignature(config, mapperInterface, method);
  }

  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //判断命令类型
    switch (command.getType()) {
      //插入类型呢
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        //调用sqlsession的insert方法
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
      //判断返回类型 和resultHandler
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
        //返回类型Many
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
        //返回类型Map类型
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
        //返回游标类型
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          //查询一个
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional() &&
              (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = OptionalUtil.ofNullable(result);
          }
        }
        break;
      case FLUSH:
      //刷新类型
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

//设置返回结果
  private Object rowCountResult(int rowCount) {
    final Object result;
    //返回结果void类型
    if (method.returnsVoid()) {
      result = null;
      //返回结果Int类型
    } else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
      result = rowCount;
      //long类型
    } else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
      result = (long)rowCount;
      //boolean类型
    } else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
      result = rowCount > 0;
      //其他返回类型
    } else {
      throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
    }
    return result;
  }

  private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
    MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
    if (!StatementType.CALLABLE.equals(ms.getStatementType())
        && void.class.equals(ms.getResultMaps().get(0).getType())) {
      throw new BindingException("method " + command.getName() 
          + " needs either a @ResultMap annotation, a @ResultType annotation," 
          + " or a resultType attribute in XML so a ResultHandler can be used as a parameter.");
    }
    //将入参转为命令
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
    } else {
      sqlSession.select(command.getName(), param, method.extractResultHandler(args));
    }
  }

  private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    List<E> result;
    Object param = method.convertArgsToSqlCommandParam(args);
    //是否需要分页
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.<E>selectList(command.getName(), param, rowBounds);
    } else {
      result = sqlSession.<E>selectList(command.getName(), param);
    }
    // issue #510 Collections & arrays support
    if (!method.getReturnType().isAssignableFrom(result.getClass())) {
      if (method.getReturnType().isArray()) {
        return convertToArray(result);
      } else {
        return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
      }
    }
    return result;
  }

//执行游标
  private <T> Cursor<T> executeForCursor(SqlSession sqlSession, Object[] args) {
    Cursor<T> result;
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.<T>selectCursor(command.getName(), param, rowBounds);
    } else {
      result = sqlSession.<T>selectCursor(command.getName(), param);
    }
    return result;
  }

  private <E> Object convertToDeclaredCollection(Configuration config, List<E> list) {
    Object collection = config.getObjectFactory().create(method.getReturnType());
    MetaObject metaObject = config.newMetaObject(collection);
    metaObject.addAll(list);
    return collection;
  }

  @SuppressWarnings("unchecked")
  private <E> Object convertToArray(List<E> list) {
    Class<?> arrayComponentType = method.getReturnType().getComponentType();
    Object array = Array.newInstance(arrayComponentType, list.size());
    if (arrayComponentType.isPrimitive()) {
      for (int i = 0; i < list.size(); i++) {
        Array.set(array, i, list.get(i));
      }
    return array;
    } else {
      return list.toArray((E[])array);
    }
  }

  private <K, V> Map<K, V> executeForMap(SqlSession sqlSession, Object[] args) {
    Map<K, V> result;
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.<K, V>selectMap(command.getName(), param, method.getMapKey(), rowBounds);
    } else {
      result = sqlSession.<K, V>selectMap(command.getName(), param, method.getMapKey());
    }
    return result;
  }

  public static class ParamMap<V> extends HashMap<String, V> {

    private static final long serialVersionUID = -2212268410512043556L;

    @Override
    public V get(Object key) {
      if (!super.containsKey(key)) {
        throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + keySet());
      }
      return super.get(key);
    }

  }

//sql命令行
  public static class SqlCommand {

	//名称
    private final String name;
    //类型
    private final SqlCommandType type;

    public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
		//获取方法名  获取方法类型     
      final String methodName = method.getName();
      final Class<?> declaringClass = method.getDeclaringClass();
      //根据接口解析出MapperStatement
      MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
          configuration);
      if (ms == null) {
      //没有解析出声明
        if(method.getAnnotation(Flush.class) != null){
          name = null;
          type = SqlCommandType.FLUSH;
        } else {
          throw new BindingException("Invalid bound statement (not found): "
              + mapperInterface.getName() + "." + methodName);
        }
      } else {
      //名字是ms的id
        name = ms.getId();
        //类型是命令类型
        type = ms.getSqlCommandType();
        if (type == SqlCommandType.UNKNOWN) {
          throw new BindingException("Unknown execution method for: " + name);
        }
      }
    }

    public String getName() {
      return name;
    }

    public SqlCommandType getType() {
      return type;
    }

    private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
        Class<?> declaringClass, Configuration configuration) {
        //签名id 是接口名.方法名
      String statementId = mapperInterface.getName() + "." + methodName;
      //配置中有这个签名id
      if (configuration.hasStatement(statementId)) {
		//如果配置中有mapperstatement 根据id返回
        return configuration.getMappedStatement(statementId);
        //接口类型等于声明类型
      } else if (mapperInterface.equals(declaringClass)) {
        return null;
      }
      for (Class<?> superInterface : mapperInterface.getInterfaces()) {
      	
      	//isAssignableFrom()方法是判断是否为某个类的父类
        if (declaringClass.isAssignableFrom(superInterface)) {
        //如果接口是子接口 从子接口中解析statement
          MappedStatement ms = resolveMappedStatement(superInterface, methodName,
              declaringClass, configuration);
          if (ms != null) {
            return ms;
          }
        }
      }
      return null;
    }
  }

  public static class MethodSignature {
	//方法签名
    private final boolean returnsMany;
    private final boolean returnsMap;
    private final boolean returnsVoid;
    private final boolean returnsCursor;
    private final boolean returnsOptional;
    private final Class<?> returnType;
    private final String mapKey;
    private final Integer resultHandlerIndex;
    private final Integer rowBoundsIndex;

	//参数名称解析
    private final ParamNameResolver paramNameResolver;

    public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
    //解析返回类型
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      
      //返回类型是接口类型
      if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;

	//判断类型Parameterized类型
      } else if (resolvedReturnType instanceof ParameterizedType) {
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
		
		//返回类型填充
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      this.returnsCursor = Cursor.class.equals(this.returnType);
      this.returnsOptional = Jdk.optionalExists && Optional.class.equals(this.returnType);
      this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      //
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      //参数名称解析
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }

    public Object convertArgsToSqlCommandParam(Object[] args) {
    
      return paramNameResolver.getNamedParams(args);
    }

    public boolean hasRowBounds() {
      return rowBoundsIndex != null;
    }

    public RowBounds extractRowBounds(Object[] args) {
      return hasRowBounds() ? (RowBounds) args[rowBoundsIndex] : null;
    }

    public boolean hasResultHandler() {
      return resultHandlerIndex != null;
    }

    public ResultHandler extractResultHandler(Object[] args) {
      return hasResultHandler() ? (ResultHandler) args[resultHandlerIndex] : null;
    }

    public String getMapKey() {
      return mapKey;
    }

    public Class<?> getReturnType() {
      return returnType;
    }

    public boolean returnsMany() {
      return returnsMany;
    }

    public boolean returnsMap() {
      return returnsMap;
    }

    public boolean returnsVoid() {
      return returnsVoid;
    }

    public boolean returnsCursor() {
      return returnsCursor;
    }

    /**
     * return whether return type is {@code java.util.Optional}
     * @return return {@code true}, if return type is {@code java.util.Optional}
     * @since 3.5.0
     */
    public boolean returnsOptional() {
      return returnsOptional;
    }

    private Integer getUniqueParamIndex(Method method, Class<?> paramType) {
      Integer index = null;
      final Class<?>[] argTypes = method.getParameterTypes();
      for (int i = 0; i < argTypes.length; i++) {
        if (paramType.isAssignableFrom(argTypes[i])) {
          if (index == null) {
            index = i;
          } else {
            throw new BindingException(method.getName() + " cannot have multiple " + paramType.getSimpleName() + " parameters");
          }
        }
      }
      return index;
    }

    private String getMapKey(Method method) {
      String mapKey = null;
      if (Map.class.isAssignableFrom(method.getReturnType())) {
        final MapKey mapKeyAnnotation = method.getAnnotation(MapKey.class);
        if (mapKeyAnnotation != null) {
          mapKey = mapKeyAnnotation.value();
        }
      }
      return mapKey;
    }
  }

}

我们可以看到MapperMethod会根据方法解析对应的XML,最后交给sqlsession去处理。

参数命令的解析交给ParamNameResolver解析 到sql中 还有返回值类型的解析

至于sqlsession如何处理,及解析的过程在下一篇中继续介绍。

2.Sql执行

SqlSession接口介绍

public interface SqlSession extends Closeable {
	//1.查询方法 One List  Map  Cursor
    <T> T selectOne(String var1);

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

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

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

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

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

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

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

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

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

    <T> Cursor<T> selectCursor(String var1, Object var2, RowBounds var3);
	
	//没有返回值的select
    void select(String var1, Object var2, ResultHandler var3);

    void select(String var1, ResultHandler var2);

    void select(String var1, Object var2, RowBounds var3, ResultHandler var4);
	
	//2.插入语句
    int insert(String var1);

    int insert(String var1, Object var2);
	
	//3.update语句
    int update(String var1);

    int update(String var1, Object var2);

	//4. 删除方法
    int delete(String var1);

    int delete(String var1, Object var2);
	
	//5.提交方法
    void commit();

    void commit(boolean var1);

	//6回滚方法
    void rollback();

    void rollback(boolean var1);

	//7.刷新关闭
    List<BatchResult> flushStatements();

    void close();

    void clearCache();
	
	//8.取配置
    Configuration getConfiguration();

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

    Connection getConnection();
}

在mybatis 3.4.0版本中新增了一个功能,查询可以返回Cusror类型的数据,类似于JDBC里的ResultSet类,当查询百万级的数据的时候,使用游标可以节省内存的消耗,不需要一次性取出所有数据,可以进行逐条处理或逐条取出部分批量处理。

Excutor接口介绍

Excutor完成整个数据库操作

可以看到Executor的主要功能都是和操作数据库相关的,执行查询,关闭链接,获取事务等等。

BaseExecutor

的属性表明:
它内部维护了localCache来localOutputParameterCache来处理缓存,至于这缓存保存的是什么,这后面专题再说。以及线程安全的延迟加载列表deferredLoads、事务对象Transaction。

BaseExecutor是一个抽象类,提供了Executor的基本实现,并将具体的查询过程作为继续保留为抽象方法。这应用了模版方法。贴出具体代码,注意看四个抽象方法

Executor还应用了包装器模式,SimpleExecutor是执行器最基本的实现,
其他Executor包装了Executor,将核心的方法委托给内部的executor执行,并在方法执行前,增加了对应特性的功能。
比如mybatis的二级缓存就是通过CachingExecutor的实现的,它会在查询前先判断时候有缓存命中,如果没有则继续将查询委托给内部的executor,并在执行后将结果进行缓存并返回结果。

公共的抽象类
内部参数

	//事物对象
	protected Transaction transaction;
    protected Executor wrapper;
    //加载列表
    protected ConcurrentLinkedQueue<BaseExecutor.DeferredLoad> deferredLoads;
    //处理缓存
    protected PerpetualCache localCache;
    protected PerpetualCache localOutputParameterCache;
    //配置信息
    protected Configuration configuration;
    protected int queryStack;
    private boolean closed;

close方法 调用rollBack 捕获异常

update语句
内容信息里 激活执行id
会清空 本地缓存 调用doUpdate

所有方法判断一下 是否已经关闭

query根据param 获取boundSql 创建CacheKey
会判断queryStack 和是否有刷新请求
resultHandler 为空的从本地获取

列表页为空 从数据库查询 否则从缓存取 结束之后栈回退

核心的查询语句

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
        if (this.closed) {
            throw new ExecutorException("Executor was closed.");
        } else {
            if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
                this.clearLocalCache();
            }

            List list;
            try {
                ++this.queryStack;
                list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
                if (list != null) {
                    this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
                } else {
                    list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
                }
            } finally {
                --this.queryStack;
            }

            if (this.queryStack == 0) {
                Iterator var8 = this.deferredLoads.iterator();

                while(var8.hasNext()) {
                    BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
                    deferredLoad.load();
                }

                this.deferredLoads.clear();
                if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                    this.clearLocalCache();
                }
            }

            return list;
        }
    }

commit语句
清空本地缓存
刷新statement

如果需要提交,执行事物提交
回滚同道理

queryFromDatabase

SimpleExecutor简单的执行器
实现了BaseExcutor的4个抽象方法

public class SimpleExecutor extends BaseExecutor {
    public SimpleExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }
	
	//更新方法
    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;

        int var6;
        try {
            //获取全局配置
            Configuration configuration = ms.getConfiguration();
            //委托给statementHandler去执行
            StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
            //执行预编译
            stmt = this.prepareStatement(handler, ms.getStatementLog());
            //执行uodate方法
            var6 = handler.update(stmt);
        } finally {
            this.closeStatement(stmt);
        }

        return var6;
    }

//调用statement的query方法
    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;

        List var9;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            stmt = this.prepareStatement(handler, ms.getStatementLog());
            var9 = handler.query(stmt, resultHandler);
        } finally {
            this.closeStatement(stmt);
        }

        return var9;
    }

    protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, (ResultHandler)null, boundSql);
        Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
        return handler.queryCursor(stmt);
    }

	//软心返回空
    public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
        return Collections.emptyList();
    }

	//预编译
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    	//首先获取连接
        Connection connection = this.getConnection(statementLog);
        //编译
        Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
        //参数解析
        handler.parameterize(stmt);
        return stmt;
    }
}

这里用到了mybatis中另一个重要的对象,StatementHandler。顾名思义这个对象是用来处理Statement的,而Statement又是我们SQL执行的主角。

BatchExecutor的属性已经表明:它内部维护了StatementList批量提交并通过batchResultList保存执行结果。

ResueExecutor

减少预编译
ResueExecutor的属性及方法表明:它内部维护了java.sql.Statement对象缓存,以重用Statement对象(对于支持预编译的数据库而言,在创建PreparedStatement时需要发送一次数据库请求预编译,而重用Statement对象主要是减少了这次预编译的网路开销)。

StatementHandler

public interface StatementHandler {
	//提供了获取Statement方法
  	Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;
	
	//设置参数的方法
  	void parameterize(Statement statement)
      throws SQLException;
	
	//批处理
  	void batch(Statement statement)
      throws SQLException;
	
	//更新操作
 	 int update(Statement statement)
      throws SQLException;
	
	//查询操作
  	<E> List<E> query(Statement statement, ResultHandler resultHandler)
      throws SQLException;

  	<E> Cursor<E> queryCursor(Statement statement)
    	  throws SQLException;
	
	//获取对应的BoundSql对象,boundsql对象表示一个sql语句,但是还未设置参数
  	BoundSql getBoundSql();
	
	//获取参数处理对象
  	ParameterHandler getParameterHandler();
}

StatementHandler也有一个抽象类的实现,BaseStatementHandler,提供了大部分的实现,并留有几个抽象方法(同样是模板模式)。

Configuration的statementHandler
//所有创建的时候都会经拦截器

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对象。它实现了StatementHandler接口,并根据MappedStatement的类型,确定不同的委托对象(又是一个代理模式的应用)。

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

}

BaseStatementHandler

拥有的参数

	//配置信息
	 protected final Configuration configuration;
    
    //对象工厂
    protected final ObjectFactory objectFactory;
    
    //类型住转化注册
    protected final TypeHandlerRegistry typeHandlerRegistry;
    
    //结果映射转化
    protected final ResultSetHandler resultSetHandler;
    
    //参数handler
    protected final ParameterHandler parameterHandler;
    
    //执行器
    protected final Executor executor;
    
    protected final MappedStatement mappedStatement;
    protected final RowBounds rowBounds;
    protected BoundSql boundSql;

重要方法

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        ErrorContext.instance().sql(this.boundSql.getSql());
        Statement statement = null;

        try {
        	//实例化 抽象方法 instantiateStatement方法就是子类自己定义获取statement对象的过程。
            statement = this.instantiateStatement(connection);
            this.setStatementTimeout(statement, transactionTimeout);
            this.setFetchSize(statement);
            return statement;
        } catch (SQLException var5) {
            this.closeStatement(statement);
            throw var5;
        } catch (Exception var6) {
            this.closeStatement(statement);
            throw new ExecutorException("Error preparing statement.  Cause: " + var6, var6);
        }
    }
SimpleExcutor

普通类型 通过 createstament
keyGenerator执行类型

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

    public int update(Statement statement) throws SQLException {
        String sql = this.boundSql.getSql();
        Object parameterObject = this.boundSql.getParameterObject();
       
       	//KeyGenerator用于生成数据库主键或将主键重置到pojo中
        KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
        int rows;
        
        if (keyGenerator instanceof Jdbc3KeyGenerator) {
            //执行  两个execute有啥区别
            statement.execute(sql, 1);
            rows = statement.getUpdateCount();
            keyGenerator.processAfter(this.executor, this.mappedStatement, statement, parameterObject);
        //查询类型
        } else if (keyGenerator instanceof SelectKeyGenerator) {
           	//执行手动查询语句  感兴趣 分析jdbc的代码
	        statement.execute(sql);
            //返回结果数
            rows = statement.getUpdateCount();
            //后置设置主键
            keyGenerator.processAfter(this.executor, this.mappedStatement, statement, parameterObject);
        } else {
        	//其他情况不设置主键
            statement.execute(sql);
            rows = statement.getUpdateCount();
        }

        return rows;
    }

    public void batch(Statement statement) throws SQLException {
        //获取sql语句
        String sql = this.boundSql.getSql();
        //加入到statement中
        statement.addBatch(sql);
    }	

    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        //获取sql语句
        String sql = this.boundSql.getSql();
        //statement执行sql
        statement.execute(sql);
        //resultHandler返回
        return this.resultSetHandler.handleResultSets(statement);
    }

    public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
        String sql = this.boundSql.getSql();
        statement.execute(sql);
        //游标查询
        return this.resultSetHandler.handleCursorResultSets(statement);
    }

    protected Statement instantiateStatement(Connection connection) throws SQLException {
        //结果类型  为空新建 直接通过connection的createStatement方法创建Statement对象
        return this.mappedStatement.getResultSetType() != null ? 
        connection.createStatement(this.mappedStatement.getResultSetType().getValue(), 1007) :
        connection.createStatement();
    }

    public void parameterize(Statement statement) throws SQLException {
    }
}

详见Statement的Executor

PreparedStatementHandler

预编译类型的

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

    public int update(Statement statement) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.execute();
        int rows = ps.getUpdateCount();
        Object parameterObject = this.boundSql.getParameterObject();
        KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
        keyGenerator.processAfter(this.executor, this.mappedStatement, ps, parameterObject);
        return rows;
    }

    public void batch(Statement statement) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.addBatch();
    }

    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.execute();
        //最后再通过ResultSetHandler将结果集转换成需要的Java对象。
        return this.resultSetHandler.handleResultSets(ps);
    }

    public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.execute();
        return this.resultSetHandler.handleCursorResultSets(ps);
    }

    protected Statement instantiateStatement(Connection connection) throws SQLException {
        String sql = this.boundSql.getSql();
        if (this.mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
            String[] keyColumnNames = this.mappedStatement.getKeyColumns();
            return keyColumnNames == null ? connection.prepareStatement(sql, 1) : connection.prepareStatement(sql, keyColumnNames);
        } else {
        //因此是通过connection的prepareStatement方法获得PrepareStatement对象
            return this.mappedStatement.getResultSetType() != null ? connection.prepareStatement(sql, this.mappedStatement.getResultSetType().getValue(), 1007) : connection.prepareStatement(sql);
        }
    }

	//预编译的prepareStatement需要设置参数,因此还要通过parameterize设置参数。
    public void parameterize(Statement statement) throws SQLException {
        this.parameterHandler.setParameters((PreparedStatement)statement);
    }
}

CallableStatementHandler

Callable类型的

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

    public int update(Statement statement) throws SQLException {
        CallableStatement cs = (CallableStatement)statement;
        cs.execute();
        int rows = cs.getUpdateCount();
        Object parameterObject = this.boundSql.getParameterObject();
        KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
        keyGenerator.processAfter(this.executor, this.mappedStatement, cs, parameterObject);
        this.resultSetHandler.handleOutputParameters(cs);
        return rows;
    }

    public void batch(Statement statement) throws SQLException {
        CallableStatement cs = (CallableStatement)statement;
        cs.addBatch();
    }

    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        CallableStatement cs = (CallableStatement)statement;
        cs.execute();
        List<E> resultList = this.resultSetHandler.handleResultSets(cs);
        this.resultSetHandler.handleOutputParameters(cs);
        return resultList;
    }

    public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
        CallableStatement cs = (CallableStatement)statement;
        cs.execute();
        Cursor<E> resultList = this.resultSetHandler.handleCursorResultSets(cs);
        this.resultSetHandler.handleOutputParameters(cs);
        return resultList;
    }

    protected Statement instantiateStatement(Connection connection) throws SQLException {
        String sql = this.boundSql.getSql();
        //CallableStatementHandler需要对过程进行转储,因此是通过connection的prepareCall方法。
        return this.mappedStatement.getResultSetType() != null ? connection.prepareCall(sql, this.mappedStatement.getResultSetType().getValue(), 1007) : connection.prepareCall(sql);
    }

    public void parameterize(Statement statement) throws SQLException {
        this.registerOutputParameters((CallableStatement)statement);
        this.parameterHandler.setParameters((CallableStatement)statement);
    }

    private void registerOutputParameters(CallableStatement cs) throws SQLException {
        List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings();
        int i = 0;

        for(int n = parameterMappings.size(); i < n; ++i) {
            ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);
            if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
                if (null == parameterMapping.getJdbcType()) {
                    throw new ExecutorException("The JDBC Type must be specified for output parameter.  Parameter: " + parameterMapping.getProperty());
                }

                if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {
                    cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());
                } else if (parameterMapping.getJdbcTypeName() == null) {
                    cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE);
                } else {
                    cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName());
                }
            }
        }

    }
}

ReuseExecutor

public class ReuseExecutor extends BaseExecutor {
	//内部多了一个statement的Map  key是sql
    private final Map<String, Statement> statementMap = new HashMap();

    public ReuseExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }

    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        //可以从mapperstatement中获取Configuration
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
        Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
        return handler.update(stmt);
    }

    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
        Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
        return handler.query(stmt, resultHandler);
    }

    protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, (ResultHandler)null, boundSql);
        Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
        return handler.queryCursor(stmt);
    }

    public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
        Iterator var2 = this.statementMap.values().iterator();

        while(var2.hasNext()) {
            Statement stmt = (Statement)var2.next();
            this.closeStatement(stmt);
        }

        this.statementMap.clear();
        return Collections.emptyList();
    }
	
	//预编译处理
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    	//获取执行语句
        BoundSql boundSql = handler.getBoundSql();
        String sql = boundSql.getSql();
        Statement stmt;
        //是否预先存储,若存了直接返回
        if (this.hasStatementFor(sql)) {
            stmt = this.getStatement(sql);
            //设置超时时间
            this.applyTransactionTimeout(stmt);
        } else {
            Connection connection = this.getConnection(statementLog);
            stmt = handler.prepare(connection, this.transaction.getTimeout());
            this.putStatement(sql, stmt);
        }

        handler.parameterize(stmt);
        return stmt;
    }

    private boolean hasStatementFor(String sql) {
        try {
            return this.statementMap.keySet().contains(sql) && !((Statement)this.statementMap.get(sql)).getConnection().isClosed();
        } catch (SQLException var3) {
            return false;
        }
    }

    private Statement getStatement(String s) {
        return (Statement)this.statementMap.get(s);
    }

    private void putStatement(String sql, Statement stmt) {
        this.statementMap.put(sql, stmt);
    }
}
BatchExecutor

批量操作

public class BatchExecutor extends BaseExecutor {
    public static final int BATCH_UPDATE_RETURN_VALUE = -2147482646;
    //示例列表
    private final List<Statement> statementList = new ArrayList();
    //批量结果
    private final List<BatchResult> batchResultList = new ArrayList();
    //当前执行语句
    private String currentSql;
    //当前示例
    private MappedStatement currentStatement;

    public BatchExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }

    public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
        //与前两种一模一样
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
        BoundSql boundSql = handler.getBoundSql();
        String sql = boundSql.getSql();
        
        Statement stmt;
        //是否是当前示例
        if (sql.equals(this.currentSql) && ms.equals(this.currentStatement)) {
            //获取最后一条
            int last = this.statementList.size() - 1;
            stmt = (Statement)this.statementList.get(last);
            this.applyTransactionTimeout(stmt);
            handler.parameterize(stmt);
            //设置返回结果
            BatchResult batchResult = (BatchResult)this.batchResultList.get(last);
            batchResult.addParameterObject(parameterObject);
            //不是当前示例
        } else {
        	//获取连接
            Connection connection = this.getConnection(ms.getStatementLog());
            stmt = handler.prepare(connection, this.transaction.getTimeout());
            handler.parameterize(stmt);
            this.currentSql = sql;
            this.currentStatement = ms;
            this.statementList.add(stmt);
            this.batchResultList.add(new BatchResult(ms, sql, parameterObject));
        }
		//批量添加
        handler.batch(stmt);
        return -2147482646;
    }

    public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;

        List var10;
        try {
        	//刷新列表
            this.flushStatements();
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
            Connection connection = this.getConnection(ms.getStatementLog());
            stmt = handler.prepare(connection, this.transaction.getTimeout());
            handler.parameterize(stmt);
            var10 = handler.query(stmt, resultHandler);
        } finally {
            this.closeStatement(stmt);
        }

        return var10;
    }

    protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
        this.flushStatements();
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, (ResultHandler)null, boundSql);
        Connection connection = this.getConnection(ms.getStatementLog());
        Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
        handler.parameterize(stmt);
        return handler.queryCursor(stmt);
    }

    public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
        boolean var17 = false;

        Statement stmt;
        ArrayList var21;
        Iterator var22;
        label179: {
            List var3;
            try {
                var17 = true;
                ArrayList results = new ArrayList();
                if (!isRollback) {
                    int i = 0;

                    for(int n = this.statementList.size(); i < n; ++i) {
                        stmt = (Statement)this.statementList.get(i);
                        this.applyTransactionTimeout(stmt);
                        BatchResult batchResult = (BatchResult)this.batchResultList.get(i);

                        try {
                            batchResult.setUpdateCounts(stmt.executeBatch());
                            MappedStatement ms = batchResult.getMappedStatement();
                            List<Object> parameterObjects = batchResult.getParameterObjects();
                            KeyGenerator keyGenerator = ms.getKeyGenerator();
                            if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
                                Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator)keyGenerator;
                                jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
                            } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) {
                                Iterator var10 = parameterObjects.iterator();

                                while(var10.hasNext()) {
                                    Object parameter = var10.next();
                                    keyGenerator.processAfter(this, ms, stmt, parameter);
                                }
                            }

                            this.closeStatement(stmt);
                        } catch (BatchUpdateException var18) {
                            StringBuilder message = new StringBuilder();
                            message.append(batchResult.getMappedStatement().getId()).append(" (batch index #").append(i + 1).append(")").append(" failed.");
                            if (i > 0) {
                                message.append(" ").append(i).append(" prior sub executor(s) completed successfully, but will be rolled back.");
                            }

                            throw new BatchExecutorException(message.toString(), var18, results, batchResult);
                        }

                        results.add(batchResult);
                    }

                    var21 = results;
                    var17 = false;
                    break label179;
                }

                var3 = Collections.emptyList();
                var17 = false;
            } finally {
                if (var17) {
                    Iterator var13 = this.statementList.iterator();

                    while(var13.hasNext()) {
                        Statement stmt = (Statement)var13.next();
                        this.closeStatement(stmt);
                    }

                    this.currentSql = null;
                    this.statementList.clear();
                    this.batchResultList.clear();
                }
            }

            var22 = this.statementList.iterator();

            while(var22.hasNext()) {
                stmt = (Statement)var22.next();
                this.closeStatement(stmt);
            }

            this.currentSql = null;
            this.statementList.clear();
            this.batchResultList.clear();
            return var3;
        }

        var22 = this.statementList.iterator();

        while(var22.hasNext()) {
            stmt = (Statement)var22.next();
            this.closeStatement(stmt);
        }

        this.currentSql = null;
        this.statementList.clear();
        this.batchResultList.clear();
        return var21;
    }
}

最后我们在梳理下SQL执行过程都通过了哪些对象:

MapperProxy(Mapper的代理对象)->MapperMethod(对应一个Mapper方法)->SqlSession->executor(执行器)->StatementHandler(Statement处理器)->Statement(最终执行SQL的对象)
MapperProxy 代理对象 调用invoke方法 使用MapperMethod进行包装,对执行类型进行判断 分为insert\update\select\delete 交给sqlSession执行,并将结果转化为resultHandler对应得返回类型
sqlsession委托给executor执行,executor拥有simeple类型(resure 缓存预编译结果)
batch 批量结果转存 ,execute通过configruation获取到statement处理器, statement 处理最后的sql对象 通过resultHandler进行包装

另一个篇章mapper的绑定

3、基础层

3.1、logging:
MyBatis使用了自己定义的一套logging接口,
根据开发者常使用的日志框架——Log4j、Log4j2、Apache Commons Log、java.util.logging、slf4j、stdout(控制台)——分别提供了适配器。

由于各日志框架的Log级别分类法有所不同(比如java.util.logging.Level提供的是All、FINEST、FINER、FINE、CONFIG、INFO、WARNING、SEVERE、OFF这九个级别,与通常的日志框架分类法不太一样),MyBatis统一提供trace、debug、warn、error四个级别,这基本与主流框架分类法是一致的(相比而言缺少Info,也许MyBatis认为自己的日志要么是debug需要的,要么就至少是warn,没有Info的必要)。

在org.apache.ibatis.logging里还有个比较特殊的包jdbc,这不是按字面意义理解把日志通过jdbc记录到数据库里,而是将jdbc操作以开发者配置的日志框架打印出来,这也就是我们在开发阶段常用的跟踪SQL语句、传入参数、影响行数这些重要的调试信息。

3.2、IO
MyBatis里的IO主要是包含两大功能:
提供读取资源文件的API、封装MyBatis自身所需要的ClassLoader和加载顺序。

3.3、reflection
在MyBatis如参数处理、结果映射这些大量地使用了反射,需要频繁地读取Class元数据、反射调用get/set,因此MyBatis提供了org.apache.ibatis.reflection对常见的反射操作进一步封装,以提供更简洁方便的API。比如我们reflect时总是要处理异常(IllegalAccessException、NoSuchMethodException),MyBatis统一处理为自定义的RuntimeException,减少代码量。

3.4、exceptions
在以Spring为代表的开源框架中,对于应用程序中无法进一步处理的异常大都转成RuntimeException来方便调用者操作,另外如频繁遇到的SQLException,JDK约定其是个Exception,从JDK的角度考虑,强制要求开发者捕获SQLException是为了能在catch/finally中关闭数据库连接,而Spring之类的框架为开发者做了资源管理的事情,自然就不需要开发者再烦心SQLException,因此封装转换成RuntimeException。MyBatis的异常体系不复杂,org.apache.ibatis.exceptions下就几个类,主要被使用的是PersistenceException。

3.5、缓存
缓存是MyBatis里比较重要的部分,
有两种缓存:
SESSION或STATEMENT作用域级别的缓存,默认是SESSION,BaseExecutor中根据MappedStatement的Id、SQL、参数值以及rowBound(边界)来构造CacheKey,并使用BaseExccutor中的localCache来维护此缓存。
全局的二级缓存,通过CacheExecutor来实现,其委托TransactionalCacheManager来保存/获取缓存,这个全局二级缓存比较复杂,后面还需要专题分析,至于其缓存的效率以及应用场景也留到那时候再分析。

3.6、数据源/连接池
MyBatis自身提供了一个简易的数据源/连接池,在org.apache.ibatis.datasource下,后面专题分析。

主要实现类是PooledDataSource,包含了最大活动连接数、最大空闲连接数、最长取出时间(避免某个线程过度占用)、连接不够时的等待时间,虽然简单,却也体现了连接池的一般原理。阿里有个“druid”项目,据他们说比proxool、c3p0的效率还要高,可以学习一下。

3.7 事务
MyBatis对事务的处理相对简单,TransactionIsolationLevel中定义了几种隔离级别,并不支持内嵌事务这样较复杂的场景,同时由于其是持久层的缘故,所以真正在应用开发中会委托Spring来处理事务实现真正的与开发者隔离。分析事务的实现是个入口,借此可以了解不扫JDBC规范方面的事情。
定义了4种隔离级别

后续将对MyBatis各个部分做详细的设计及源代码分析,由于读取和解析SqlMapConfig.xml和SqlMap.xml的逻辑与各个模块的相关性较强,因此将把这部分内容与在各模块组合在一起分析。

DeafultSqlSession
delete调用update
commit 调用excutor的commit 重新reset
autoCommit/dity/force
update 使用ms的update
select 都调用的selectList excutor query 会重新设置ErrorContext

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

        return var5;
    }

首先是从configuration中根据传入的statement获取MappedStatement对象,这里的statement就是 Mapper的namespace + SQL的id 构成的一个id。configuration会缓存这个id和对应的MappedStatement对象。

MappedStatement对象是Mybatis中重要的一个对象,用来表示一个XML中的一个SQL节点。我们会在之后再去具体了解及configuration解析XML的过程。

insert调用的update
无返回值的select 拥有resultHandler

入参包装map 如果是集合类型collection list类型 数组类型 array

DefaultSqlSessionFactory

4.了解Mybatis全部配置信息

初次学习mybatis的时候,

部件关系图

在这里插入图片描述

Mybatis流程图

这里写图片描述
Mybatis底层还是采用jdbc操作数据。

只是通过 SqlSessionFactory,SqlSession Executor,StatementHandler,ParameterHandler,ResultHandler和TypeHandler等几个处理器封装了这些过程。

其中StatementHandler用通过ParameterHandler进行参数预编译与ResultHandler进行结果处理。
而ParameterHandler与ResultHandler都使用TypeHandler进行映射。
处理流程图如下
这里写图片描述
用户通过SqlSessionFactoryBuilder().build()方法作为入口

build()方法内部通过调用内部parse()方法对配置文件进行解析并初始化MyBattis

最后返回SqlSessionFactory

Facotry的形成过程

这里写图片描述

sqlsession的产生

这里写图片描述

Mapper的创建
这里写图片描述
这里面使用了代理

执行器Executor接口

public interface Executor {
	//用于有返回值中的handler
    ResultHandler NO_RESULT_HANDLER = null;

	//更新方法
    int update(MappedStatement var1, Object var2) throws SQLException;

	//查询方法
    <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException;

    <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;

    <E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException;

//回滚提交
    List<BatchResult> flushStatements() throws SQLException;

    void commit(boolean var1) throws SQLException;

    void rollback(boolean var1) throws SQLException;

//缓存相关
    CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4);

    boolean isCached(MappedStatement var1, CacheKey var2);

    void clearLocalCache();

    void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class<?> var5);

    Transaction getTransaction();
//清理相关
    void close(boolean var1);

    boolean isClosed();

    void setExecutorWrapper(Executor var1);
}

DefaultSqlSessionFactory
作呕用主要 获取会话来自数据源配置 内部有一个configruation类

默认自动提交false
默认的执行器类型
隔离级别默认null

DefaultSqlSession

openSessionFromDatasource

重要方法

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
           //从事物工厂创建事物 根据环境中的数据源
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            //创建执行器
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

重要方法二

private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
        DefaultSqlSession var8;
        try {
            boolean autoCommit;
            try {
                autoCommit = connection.getAutoCommit();
            } catch (SQLException var13) {
                autoCommit = true;
            }

            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            //这个从connection创建事物
            Transaction tx = transactionFactory.newTransaction(connection);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var14, var14);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

默认的typeHandler
默认的类型处理器
类型处理器

Java 类型

JDBC 类型

BooleanTypeHandler

java.lang.Boolean, boolean

数据库兼容的 BOOLEAN

ByteTypeHandler

java.lang.Byte, byte

数据库兼容的 NUMERIC 或 BYTE

ShortTypeHandler

java.lang.Short, short

数据库兼容的 NUMERIC 或 SHORT INTEGER

IntegerTypeHandler

java.lang.Integer, int

数据库兼容的 NUMERIC 或 INTEGER

LongTypeHandler

java.lang.Long, long

数据库兼容的 NUMERIC 或 LONG INTEGER

FloatTypeHandler

java.lang.Float, float

数据库兼容的 NUMERIC 或 FLOAT

DoubleTypeHandler

java.lang.Double, double

数据库兼容的 NUMERIC 或 DOUBLE

BigDecimalTypeHandler

java.math.BigDecimal

数据库兼容的 NUMERIC 或 DECIMAL

StringTypeHandler

java.lang.String

CHAR, VARCHAR

ClobReaderTypeHandler

java.io.Reader

ClobTypeHandler

java.lang.String

CLOB, LONGVARCHAR

NStringTypeHandler

java.lang.String

NVARCHAR, NCHAR

NClobTypeHandler

java.lang.String

NCLOB

BlobInputStreamTypeHandler

java.io.InputStream

ByteArrayTypeHandler

byte[]

数据库兼容的字节流类型

BlobTypeHandler

byte[]

BLOB, LONGVARBINARY

DateTypeHandler

java.util.Date

TIMESTAMP

DateOnlyTypeHandler

java.util.Date

DATE

TimeOnlyTypeHandler

java.util.Date

TIME

SqlTimestampTypeHandler

java.sql.Timestamp

TIMESTAMP

SqlDateTypeHandler

java.sql.Date

DATE

SqlTimeTypeHandler

java.sql.Time

TIME

ObjectTypeHandler

Any

OTHER 或未指定类型

EnumTypeHandler

Enumeration Type

VARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引)

EnumOrdinalTypeHandler

Enumeration Type

任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的索引(而不是名称)。

InstantTypeHandler

java.time.Instant

TIMESTAMP

LocalDateTimeTypeHandler

java.time.LocalDateTime

TIMESTAMP

LocalDateTypeHandler

java.time.LocalDate

DATE

LocalTimeTypeHandler

java.time.LocalTime

TIME

OffsetDateTimeTypeHandler

java.time.OffsetDateTime

TIMESTAMP

OffsetTimeTypeHandler

java.time.OffsetTime

TIME

ZonedDateTimeTypeHandler

java.time.ZonedDateTime

TIMESTAMP

YearTypeHandler

java.time.Year

INTEGER

MonthTypeHandler

java.time.Month

INTEGER

YearMonthTypeHandler

java.time.YearMonth

VARCHAR or LONGVARCHAR

JapaneseDateTypeHandler

java.time.chrono.JapaneseDate

DATE

KeyGenerator

KeyGenerator接口定义了2个函数:
KeyGenerator用于生成数据库主键或将主键重置到pojo中

public interface KeyGenerator {
	//执行sql之前写入到pojo中
    void processBefore(Executor var1, MappedStatement var2, Statement var3, Object var4);
	//执行sql之后写入到pojo中
    void processAfter(Executor var1, MappedStatement var2, Statement var3, Object var4);
}

默认实现有3个
NoKeyGenerator
没有执行任何操作,并且是Mybatis的默认实现

public class NoKeyGenerator implements KeyGenerator {
    public static final NoKeyGenerator INSTANCE = new NoKeyGenerator();

    public NoKeyGenerator() {
    }
	//全部都是空方法
    public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    }

    public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    }
}

Jdbc3KeyGenerator
适用于可以自动生成主键的sql(自增等),由于Statement.execute执行后返回的是操作行数,并不会返回主键,当配置了

<insert id="insert" useGeneratedKeys="true" keyProperty="id">

该函数会自动将id赋值到keyProperty对应的javabean属性中

public class Jdbc3KeyGenerator implements KeyGenerator {
    public static final Jdbc3KeyGenerator INSTANCE = new Jdbc3KeyGenerator();

    public Jdbc3KeyGenerator() {
    }

	//前置处理什么都不做
    public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    }
	
	//后值处理
    public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
        this.processBatch(ms, stmt, this.getParameters(parameter));
    }
	
	//真正的处理方法
    public void processBatch(MappedStatement ms, Statement stmt, Collection<Object> parameters) {
        ResultSet rs = null;

        try {
            rs = stmt.getGeneratedKeys();
            Configuration configuration = ms.getConfiguration();
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
           
            //获取配置属性的字段名
            String[] keyProperties = ms.getKeyProperties();
           
            //返回的id
            ResultSetMetaData rsmd = rs.getMetaData();
            TypeHandler<?>[] typeHandlers = null;
            MetaObject metaParam;
            
            //主键为空,并且返回个数多
            if (keyProperties != null && rsmd.getColumnCount() >= keyProperties.length) {
                for(Iterator var10 = parameters.iterator(); 
                		var10.hasNext(); 
                			this.populateKeys(rs, metaParam, keyProperties, typeHandlers)) {
                			//批量循环用于insert语句
                    Object parameter = var10.next();
                    //推出条件
                    if (!rs.next()) {
                        break;
                    }
					//将javaBean进行包装
                    metaParam = configuration.newMetaObject(parameter);
                    if (typeHandlers == null) {
                    //类型转化
                        typeHandlers = this.getTypeHandlers(typeHandlerRegistry, metaParam, keyProperties, rsmd);
                    }
                }
            }
        } catch (Exception var20) {
            throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + var20, var20);
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (Exception var19) {
                }
            }

        }

    }

    private Collection<Object> getParameters(Object parameter) {
        Collection<Object> parameters = null;
        if (parameter instanceof Collection) {
            parameters = (Collection)parameter;
        } else if (parameter instanceof Map) {
            Map parameterMap = (Map)parameter;
            if (parameterMap.containsKey("collection")) {
                parameters = (Collection)parameterMap.get("collection");
            } else if (parameterMap.containsKey("list")) {
                parameters = (List)parameterMap.get("list");
            } else if (parameterMap.containsKey("array")) {
                parameters = Arrays.asList((Object[])((Object[])parameterMap.get("array")));
            }
        }

        if (parameters == null) {
            parameters = new ArrayList();
            ((Collection)parameters).add(parameter);
        }

        return (Collection)parameters;
    }

    private TypeHandler<?>[] getTypeHandlers(TypeHandlerRegistry typeHandlerRegistry, MetaObject metaParam, String[] keyProperties, ResultSetMetaData rsmd) throws SQLException {
        TypeHandler<?>[] typeHandlers = new TypeHandler[keyProperties.length];

        for(int i = 0; i < keyProperties.length; ++i) {
            if (metaParam.hasSetter(keyProperties[i])) {
                TypeHandler th;
                try {
                    Class<?> keyPropertyType = metaParam.getSetterType(keyProperties[i]);
                    th = typeHandlerRegistry.getTypeHandler(keyPropertyType, JdbcType.forCode(rsmd.getColumnType(i + 1)));
                } catch (BindingException var9) {
                    th = null;
                }

                typeHandlers[i] = th;
            }
        }

        return typeHandlers;
    }

    private void populateKeys(ResultSet rs, MetaObject metaParam, String[] keyProperties, TypeHandler<?>[] typeHandlers) throws SQLException {
        for(int i = 0; i < keyProperties.length; ++i) {
            String property = keyProperties[i];
            TypeHandler<?> th = typeHandlers[i];
            if (th != null) {
                Object value = th.getResult(rs, i + 1);//获取db->javabean中的值
                //设置到javaBean到对应的属性值
                metaParam.setValue(property, value);
            }
        }

    }
}

SelectKeyGenerator:
通过自定义sql手动获取主键值,有2种配置,before和after
before既是在insert之前设置到pojo中作为参数一起insert到db
after即为在insert之后,通过自定义sql获取并设置到pojo中

<selectKey resultType="java.lang.Integer" keyProperty="id" order="BEFORE">  
      select max(id) from TB_USER  
</selectKey>
public class SelectKeyGenerator implements KeyGenerator {
    public static final String SELECT_KEY_SUFFIX = "!selectKey";
    //决定执行前后执行
    private final boolean executeBefore;
    //存储keyStatement
    private final MappedStatement keyStatement;

    public SelectKeyGenerator(MappedStatement keyStatement, boolean executeBefore) {
        this.executeBefore = executeBefore;
        this.keyStatement = keyStatement;
    }

    public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
        if (this.executeBefore) {
            this.processGeneratedKeys(executor, ms, parameter);
        }

    }

    public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
        if (!this.executeBefore) {
            this.processGeneratedKeys(executor, ms, parameter);
        }

    }

    private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
        try {
        	//对象不为空、并且主键字段不为空
            if (parameter != null && this.keyStatement != null && this.keyStatement.getKeyProperties() != null) {
                String[] keyProperties = this.keyStatement.getKeyProperties();
                Configuration configuration = ms.getConfiguration();
                MetaObject metaParam = configuration.newMetaObject(parameter);
                if (keyProperties != null) {
                	//同过configruation构建执行器
                    Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
                    //执行查询
                    List<Object> values = keyExecutor.query(this.keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
                    //查询结果为空
                    if (values.size() == 0) {
                        throw new ExecutorException("SelectKey returned no data.");
                    }
					//结果超过1条
                    if (values.size() > 1) {
                        throw new ExecutorException("SelectKey returned more than one value.");
                    }
					//取返回结果
                    MetaObject metaResult = configuration.newMetaObject(values.get(0));
                    if (keyProperties.length == 1) {
                    	//返回结果是否有值
                        if (metaResult.hasGetter(keyProperties[0])) {
                            this.setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
                        } else {
                            this.setValue(metaParam, keyProperties[0], values.get(0));
                        }
                    } else {
                    	//处理多配置  后续再看
                        this.handleMultipleProperties(keyProperties, metaParam, metaResult);
                    }
                }
            }

        } catch (ExecutorException var10) {
            throw var10;
        } catch (Exception var11) {
            throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + var11, var11);
        }
    }

    private void handleMultipleProperties(String[] keyProperties, MetaObject metaParam, MetaObject metaResult) {
        String[] keyColumns = this.keyStatement.getKeyColumns();
        if (keyColumns != null && keyColumns.length != 0) {
            if (keyColumns.length != keyProperties.length) {
                throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
            }

            for(int i = 0; i < keyProperties.length; ++i) {
                this.setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
            }
        } else {
            String[] var5 = keyProperties;
            int var6 = keyProperties.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                String keyProperty = var5[var7];
                this.setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));
            }
        }

    }

    private void setValue(MetaObject metaParam, String property, Object value) {
       //判断字段有没有set方法
        if (metaParam.hasSetter(property)) {
            metaParam.setValue(property, value);
        } else {
            throw new ExecutorException("No setter found for the keyProperty '" + property + "' in " + metaParam.getOriginalObject().getClass().getName() + ".");
        }
    }
}

通用mapper支持多主键设置
唯一的区别

  TypeHandler th;
                try {
                    Class<?> keyPropertyType = metaParam.getSetterType(keyProperties[i]);
                    th = typeHandlerRegistry.getTypeHandler(keyPropertyType, JdbcType.forCode(rsmd.getColumnType(i + 1)));//原生的多了一个类型转化
                } catch (BindingException var9) {
                    th = null;
                }

通用mapper的处理

                Class<?> keyPropertyType = metaParam.getSetterType(keyProperties[i]);
                TypeHandler<?> th = typeHandlerRegistry.getTypeHandler(keyPropertyType);
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值