mybatis源码 01

在这里插入图片描述
01.ORM 比较JDBC 和mybatis的区别
在这里插入图片描述
在这里插入图片描述
02.Mybatis 结构

在这里插入图片描述
在这里插入图片描述

Mybatis 整体执行流程
在这里插入图片描述
在这里插入图片描述

03.Mybatis 使用到的设计模式

1.Builder 模式 : SQLSessionFactoryBuilder、Environment

在Mybatis 环境的初始化过程中,
SqlSessionFactoryBuilder 会调用XMLConfigBuilder 读取 mybatis-config.xml 和所有的 *Mapper.xml 文件,
构建Mybatis 核心对象Configuration ,然后将Configuration 对象作为参数构建一个 SqlSessionFactory。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这个过程中,Builder 会读取文件或配置,然后做XpathParser 解析,配置或语法解析,反射生成对象,存入结果缓存等步骤,这么多的工作不是一个构造函数所能包括的,因此大量采用了Builder 模式来解决。

2.工厂模式 :SqlSessionFactory、TransactionFactory、LogFactory

在Mybatis 中使用了简单工厂模式,因为没有什么复杂的业务逻辑。
Mybatis 中执行sql 语句、获取Mappers、管理事务的核心接口SqlSession 的创建过程使用到了工厂模式,有一个SqlSessionFactory 来负责 SqlSession 的创建。

3.单例模式 : ErrorContext、LogFactory

4.代理模式 :Mybatis 实现核心,比如MapperProxy、ConnectionLogger

代理模式可以认为是Mybatis 核心使用模式,正式由于这个模式,我们只需要编写Mapper 接口,不需要实现,由Mybatis 后台帮我们完成具体SQL 的执行。
当我们使用Configuration 的getMapper 方法时,会调用mapperRegistry.getMapper 方法,而该方法又会调用mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理。

在这里插入图片描述
5.模板方法模式 :BaseExecutor、SimpleExecutor、BaseTypeHandler 和其子类

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

04.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"/>
    <typeAliases>
 
        <package name=""/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
	        <transactionManager type="JDBC"></transactionManager>
	        <dataSource type="POOLED">
	            <property name="driver" value="${database.driver}"/>
	            <property name="url" value="${database.url}"/>
	            <property name="username" value="${database.username}"/>
	            <property name="password" value="${database.password}"/>
	        </dataSource>
       </environment>
    </environments>
    <mappers>
        <mapper resource=""></mapper>
    </mappers>
 
</configuration>

01.properties 元素

作用:一般用于配置外部数据库连接信息
在核心配置文件中,通过 properties 标签来引用外部的属性文件,通过 resource 属性来指定外部属性文件路径。
例如:
在resource目录下,创建一个JDBC.properties文件

内容如下:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=root

这是datasource的属性赋值
在这里插入图片描述

02配置环境(environments)

配置环境(environments) MyBatis 可以配置成适应多种环境,也就是配置多个environment子元素,这种机制有助于将 SQL 映射应用于多种数据库之中 注意:
environments的default属性取值要和其中一个environment的id属性取值一致。

03.transactionManager 元素

transactionManager 元素的type属性表示事务管理器类型,在MyBatis中有两种类型:

JDBC – 这种方式是直接使用了JDBC的事务提交和回滚设置

MANAGED(托管) –这种方式从来不提交或回滚一个连接。而是让容器来管理事务的整个生命周期(比如 Spring)

04.dataSource元素
dataSource元素中主要配置了 JDBC 连接对象的资源,它的type属性表示数据源类型,内建的数据源类型有三种:

UNPOOLED: 每次被请求时简单打开和关闭连接

POOLED:这是JDBC连接对象的数据库连接池的实现,用来避免创建新的连接实例

JNDI:这个数据源的实现是为了使用如Spring或应用服务器这类的容器

property子元素中配置了具体的数据库连接信息

driver – 是 JDBC 驱动的 Java 类的完全限定名

url – 是数据库的 JDBC URL 地址

username – 登录数据库的用户名

password – 登录数据库的密码

05.mappers元素
告诉 MyBatis 到哪里去找到这些sql语句。
mappers(映射器) 使用相对于类路径的资源引用
mapper resource=“asia/xiaojiang/mybatis03/dao/UserMapper.xml”


05.MyBatis映射文件
namespace属性
映射文件的根元素为mapper,它的namespace属性为映射器接口的完全限定名

以下子元素的id属性值为接口中的某个方法名称

insert – 映射插入语句

update – 映射更新语句

delete – 映射删除语句

select – 映射查询语句

<?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">
    <!-- namespace代表唯一标识符 -->
<mapper namespace="com.mybatis.mapper.UserMapper">
    <select id="selectAllUsers"    
            resultType="com.mybatis.entity.User">
        select * from user
    </select>
</mapper>

06.具体流程

在这里插入图片描述

public class MybatisTest {

    public static void main(String[] args) throws IOException {
        //1. 读取mybatis-config.xml 文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

        //2. 构建SqlSessionFactory(创建了DefaultSqlSessionFactory)
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //3. 打开SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //4. 通过 SqlSession 获取到 Mapper的代理对象(MapperProxy)
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //5. 获取mapper 接口对象的方法操作数据库
        List<SysUser> sysUsers = mapper.selectByIdList(Arrays.asList(1L));
        System.out.println("查询结果为:" + sysUsers.size());
    }
}

我们可以轻易的发现每次去请求数据库操作都需要通过 SqlSessionFactory 去获取到 SqlSession,而 SqlSessionFactory 是通过 SqlSessionFactoryBuilder 构造出来的, 并且最后请求操作完成后都关闭了SqlSession。

1.SqlSessionFactory 一个应用程序中最好只有1个,即单列。
2.SqlSessionFactoryBuilder 只有一个作用: 创建 SqlSessionFactory对象。
3.一个SqlSession应该仅存活于一个业务请求中都有一个SqlSession,也可以说一个SqlSession对应一次数据库会话,它不是永久存活的,每次访问数据库时都需要创建它,并且访问完成后都必须执行会话关闭

详细讲解:

01.SqlSessionFactory

一.SqlSessionFactory 来源:

每一个MyBatis的应用程序都以一个SqlSessionFactory 对象的实例为核心 。

SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象来获得 。 这个是建造者模式。

SqlSessionFactoryBuilder会调用XMLConfigBuilder.parse()读取所有的MybatisMapConfig.xml,构建Mybatis运行的核心对象Configuration对象,然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。

在这里插入图片描述

其中XMLConfigBuilder在构建Configuration对象时,也会调用XMLMapperBuilder用于读取*.Mapper文件,而XMLMapperBuilder会使用XMLStatementBuilder来读取和build所有的SQL语句。

在这里插入图片描述

SqlSessionFactoryBuilder:第二个方法
在这里插入图片描述

package org.example.utils;
 
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 MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }
}

二.SqlSessionFactory用法:

在Mybatis中比如SqlSessionFactory使用的是工厂模式,该工厂没有那么复杂的逻辑,是一个简单工厂模式。

SqlSessionFactory用来创建SqlSession对象.

SqlSessionFactory:

//SqlSessionFactory接口源码如下所示:

package org.apache.ibatis.session;

import java.sql.Connection;

public interface SqlSessionFactory {

  SqlSession openSession();//这个方法最经常用,用来创建SqlSession对象.

  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}

在DefaultSqlSessionFactory的默认工厂实现里,有一个方法可以看出工厂怎么产出一个产品:

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

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

	 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
	    executorType = executorType == null ? defaultExecutorType : executorType;
	    //defaultExecutorType 为空的话则为:ExecutorType.SIMPLE
	    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
	    Executor 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 (cacheEnabled) {
	      executor = new CachingExecutor(executor);
	    }
	    executor = (Executor) interceptorChain.pluginAll(executor);
	    return executor;
	 }

整个SqlSession 的创建分 3个步骤:

1、 获取到 TransactionFactory 事务工厂对象 ( 如果有仔细看过 SqlSessionFactoryBean.buildSqlSessionFactory() 过程的同学,应该能够看到是 SpringManagedTransactionFactory )
2、 通过 TransactionFactory 获取了一个 事务 Transaction
3、 根据 execType(默认是 SIMPLE ) 获取了一个Executor (真正执行数据库操作的对象)
4、 创建并返回 DefaultSqlSession(SqlSession实现类) 对象


通过源码我们知道每次 SqlSession(准确地说是 DefaultSqlSession )的创建都会 有一个 Transaction(在Mybatis-Spring 中 是 SpringManagedTransaction ) 事务对象 的生成。也就是说:

1、 一个事务 Transaction 对象与一个 SqlSession 对象 是一一对应的关系。
2、 同一个SqlSession 不管执行多少次数据库操作。只要没有执行close,那么整个操作都是在同一个 Transaction 中执行的。


此外:
这是一个openSession调用的底层方法,该方法先从configuration读取对应的环境配置,然后初始化TransactionFactory获得一个Transaction对象,然后通过Transaction获取一个Executor对象,最后通过configuration、Executor、是否autoCommit三个参数构建了SqlSession。

在这里其实也可以看到端倪,SqlSession的执行,其实是委托给对应的Executor来进行的

在这里插入图片描述

02.SqlSession

SqlSession是MyBatis的关键对象,是执行持久化操作的独享,类似于JDBC中的Connection
SqlSession是一个接口

//SqlSession接口源码如下所示:

package org.apache.ibatis.session;

import java.io.Closeable;
import java.sql.Connection;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.executor.BatchResult;

public interface SqlSession extends Closeable {

  <T> T selectOne(String statement);

  <T> T selectOne(String statement, Object parameter);

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

  <E> List<E> selectList(String statement, Object parameter);

  <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);

  <K, V> Map<K, V> selectMap(String statement, String mapKey);

  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);

  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);

  void select(String statement, Object parameter, ResultHandler handler);

  void select(String statement, ResultHandler handler);

  void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);

  int insert(String statement);

  int insert(String statement, Object parameter);

  int update(String statement);

  int update(String statement, Object parameter);

  int delete(String statement);

  int delete(String statement, Object parameter);

  void commit();

  void commit(boolean force);

  void rollback();

  void rollback(boolean force);

  List<BatchResult> flushStatements();

  void close();

  void clearCache();

  Configuration getConfiguration();

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

  Connection getConnection();
}

可以看出来这个接口主要定义类关于CRUD、数据库事务、数据库刷新等相关操作。下面看它的默认实现类:DefaultSqlSession在这里插入图片描述
部分具体代码:

public class DefaultSqlSession implements SqlSession {

  private final Configuration configuration;
  private final Executor executor;

  private final boolean autoCommit;
  private boolean dirty;
  private List<Cursor<?>> cursorList;


public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
  }

  public DefaultSqlSession(Configuration configuration, Executor executor) {
    this(configuration, executor, false);
  }

  @Override
  public <T> T selectOne(String statement) {
    return this.selectOne(statement, null);
  }

  @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);
    if (list.size() == 1) {
      return list.get(0);
    } else if (list.size() > 1) {
      throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
      return null;
    }
  }

  @Override
  public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
    return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
  }

  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
    return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
  }

  @Override
  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
    final List<? extends V> list = selectList(statement, parameter, rowBounds);
    final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
            configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
    final DefaultResultContext<V> context = new DefaultResultContext<>();
    for (V o : list) {
      context.nextResultObject(o);
      mapResultHandler.handleResult(context);
    }
    return mapResultHandler.getMappedResults();
  }

  @Override
  public <T> Cursor<T> selectCursor(String statement) {
    return selectCursor(statement, null);
  }

  @Override
  public <T> Cursor<T> selectCursor(String statement, Object parameter) {
    return selectCursor(statement, parameter, RowBounds.DEFAULT);
  }

  @Override
  public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
      registerCursor(cursor);
      return cursor;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  @Override
  public <E> List<E> selectList(String statement) {
    return this.selectList(statement, null);
  }

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

  @Override
  public void select(String statement, Object parameter, ResultHandler handler) {
    select(statement, parameter, RowBounds.DEFAULT, handler);
  }

  @Override
  public void select(String statement, ResultHandler handler) {
    select(statement, null, RowBounds.DEFAULT, handler);
  }

  @Override
  public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  @Override
  public int insert(String statement) {
    return insert(statement, null);
  }

  @Override
  public int insert(String statement, Object parameter) {
    return update(statement, parameter);
  }

  @Override
  public int update(String statement) {
    return update(statement, null);
  }

  @Override
  public int update(String statement, Object parameter) {
    try {
      dirty = true;
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  @Override
  public int delete(String statement) {
    return update(statement, null);
  }

  @Override
  public int delete(String statement, Object parameter) {
    return update(statement, parameter);
  }

  @Override
  public void commit() {
    commit(false);
  }

  @Override
  public void commit(boolean force) {
	    try {
	      executor.commit(isCommitOrRollbackRequired(force));
	      dirty = false;
	    } catch (Exception e) {
	      throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);
	    } finally {
	      ErrorContext.instance().reset();
	    }
	}
	@Override
  public <T> T getMapper(Class<T> type) {
    return configuration.getMapper(type, this);
  }
}

首先要执行sql,先运行这个方法 DefaultSqlSession 的 getMapper 方法:


    // type为Mapper接口的类型,例如interface org.example.dao.EmployeeMapper
@Override
  public <T> T getMapper(Class<T> type) {
    return configuration.getMapper(type, this);//  这个  是 DefaultSqlSession 的一个属性  configuration 
  }

configuration.getMapper(type, sqlSession)

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

在这里插入图片描述
mapperRegistry.getMapper(type, sqlSession)

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 通过knownMappers获取Mapper接口对应的Mapper代理工厂
    // knownMappers在注册的时候已经存好我们的mapper接口了,
    // 一个是interface org.example.dao.EmployeeMapper,一个是interface org.example.dao.EmployeeMapperPlus
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
        // 通过该Mapper代理工厂生成一个代理对象
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

mapperProxyFactory.newInstance(sqlSession)

  public T newInstance(SqlSession sqlSession) {
    // 这里mapperInterface也就是org.example.dao.EmployeeMapper
    // 创建MapperProxy,它实现了InvocationHandler
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    // 是通过代理返回一个Mapper的代理对象org.apache.ibatis.binding.MapperProxy@11d8ae8b
    return newInstance(mapperProxy);
  }

mapperProxyFactory.newInstance(mapperProxy)

  protected T newInstance(MapperProxy<T> mapperProxy) {
    // 调用Proxy.newProxyInstance创建MapperProxy的代理对象
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

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

最后返回一个MapperProxy的代理对象,MapperProxy类作为Mapper接口的实现类代理对象,可利用反射来代理完成业务方法的实现。

03.MapperProxy:
动态代理类MapperProxy,调用Mapper接口的所有方法都会先调用到这个代理类的invoke方法(注意由于Mybatis中的Mapper接口没有实现类,所以MapperProxy这个代理对象中没有委托类,也就是说MapperProxy干了代理类和委托类的事情)。好了下面重点看下invoke方法。

MapperProxy:

//MapperProxy代理类
  public class MapperProxy<T> implements InvocationHandler, Serializable
{
	 
	  private static final long serialVersionUID =6424540398559729838L;
	  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;
	}

	/**
    * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
    * method:我们所要调用某个对象真实的方法的Method对象
    * args:指代代理对象方法传递的参数
    */
	 
	  @Override
	  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		  try {
		  // 如果方法是Object类的方法,则直接反射执行
			  if (Object.class.equals(method.getDeclaringClass())) {
			  //Method.invoke()方法的功能:通过反射运行指定的方法,这里就执行了sql语句了
			 	 return method.invoke(this, args);
			  } else if (isDefaultMethod(method)) {
		 	 	return invokeDefaultMethod(proxy, method, args);
		 	  }
		  } catch (Throwable t) {
		 	 throw ExceptionUtil.unwrapThrowable(t);
		  }
		  //如果不是,从缓存中获取MapperMethod,如果为空则创建并加入缓存,然后执行sql语句
		  final MapperMethod mapperMethod = cachedMapperMethod(method);
		  return mapperMethod.execute(sqlSession, args);
	}

	private MapperMethod cachedMapperMethod(Method method) {
	    // 根据方法从缓存中获取
	    MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
	    if (mapperMethod == null) {
	        // 不存在则创建一个
	        mapperMethod = new MapperMethod(this.mapperInterface, method,this.sqlSession.getConfiguration());
	        // 放入缓存
	        this.methodCache.put(method, mapperMethod);
	    }
	    return mapperMethod;
	}
  }

MapperMethod:

private final MapperMethod.SqlCommand command;
private final MapperMethod.MethodSignature method;

public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
    this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
}

SqlCommand一个内部类 封装了SQL标签的类型 insert update delete select
MethodSignature一个内部类 封装了方法的参数信息 返回类型信息等


MapperProxy的invoke方法非常简单,主要干的工作就是创建MapperMethod对象或者是从缓存中获取MapperMethod对象。获取到这个对象后执行execute方法。

所以这边需要进入MapperMethod的execute方法:这个方法判断你当前执行的方式是增删改查哪一种,并通过SqlSession执行相应的操作。(这边以sqlSession.selectOne这种方式进行分析~)

MapperMethod的execute
在这里插入图片描述

public Object execute(SqlSession sqlSession, Object[] args) {
	  Object result;
	  //判断是CRUD那种方法
	  switch (command.getType()) {
		  case INSERT: {
		  	 Object param = method.convertArgsToSqlCommandParam(args);
		 	 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:
		  if (method.returnsVoid() && method.hasResultHandler()) {// 返回类型为void
			  executeWithResultHandler(sqlSession, args);
			  result = null;
		  } else if (method.returnsMany()) { // 返回类型为集合或数组
		  	  result = executeForMany(sqlSession, args);
		  } else if (method.returnsMap()) {
		  	  result = executeForMap(sqlSession, args);
		  } else if (method.returnsCursor()) {
		      result = executeForCursor(sqlSession, args);
		  } else {
			  Object param = method.convertArgsToSqlCommandParam(args);
			  result = sqlSession.selectOne(command.getName(), param);
		  }
	  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;
}

例子:

sqlSession.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);
    if (list.size() == 1) {
      return list.get(0);
    } else if (list.size() > 1) {
      throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
      return null;
    }
  }

sqlSession.selectOne方法会会调到DefaultSqlSession的selectList方法。
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();
    }
  }

这个方法获取了获取了MappedStatement对象,并最终调用了Executor的query方法。
然后,通过一层一层的调用,最终会来到doQuery方法

04.Executor
在Mybatis中,sqlSession的SQL执行,都是委托给Executor实现的,Executor包含以下结构:在这里插入图片描述

其中的BaseExecutor就采用了模板方法模式,它实现了大部分的SQL执行逻辑,然后把以下几个方法交给子类定制化完成:

protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;

protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException;

protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds,
                                       ResultHandler resultHandler, BoundSql boundSql) throws SQLException;

然后,通过一层一层的调用(这边省略了缓存操作的环节,会在后面的文章中介
绍),最终会来到doQuery方法, 这儿咱们就随便找个Excutor看看doQuery方
法的实现吧,我这儿选择了SimpleExecutor:

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();
  //内部封装了ParameterHandler和ResultSetHandler
  StatementHandler handler = configuration.newStatementHandler(wrapper,ms, parameter, rowBounds, resultHandler, boundSql);
  stmt = prepareStatement(handler, ms.getStatementLog());
  //StatementHandler封装了Statement, 让 StatementHandler 去处理
  return handler.<E>query(stmt, resultHandler);
  } finally {
  closeStatement(stmt);
  }
  }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值