MyBatis执行sql的整个流程

MyBatis执行sql的整个流程

大致过程:启动->解析配置文件->创建executor->绑定参数->执行sql->结果集映射

扫描配置

@MapperScan,配置了@Import(MapperScannerRegistrar.class)。MapperScannerRegistrar 用于注册 MapperScannerConfigurer BeanDefinition。

MapperScannerConfigurer 主要实现了 BeanDefinitionRegistryPostProcessor 接口。
其 postProcessBeanDefinitionRegistry 方法,通过 ClassPathMapperScanner 将扫描的信息转化为 MapperFactoryBean BeanDefinition。

获取代理对象及调用具体过程

1、Mapper 的获取:

  • 创建sqlSessionFactory对象
    • SqlSessionFactoryBuilder 创建Configuration对象,然后根据Configuration对象创建SqlSessionFactory。Configuration =>(作为构造器参数)=> 返回 DefaultSqlSessionFactory。
    • mybatis-spring,由 SqlSessionFactoryBean 创建 SqlSessionFactory。
    • mybatis-plus,MybatisPlusAutoConfiguration 中由 MybatisSqlSessionFactoryBean 创建 SqlSessionFactory。
  • 创建sqlSession对象
    • SqlSessionFactory 创建SqlSession对象。
    • => DefaultSqlSessionFactory.openSession => openSessionFromDataSource =>
      先创建Executor,再根据 Configuration、Executor(默认使用SimpleExecutor)、autoCommit 返回 DefaultSqlSession。
    • mybatis-spring、mybatis-plus中类型为:SqlSessionTemplate。
  • 获取Mapper接口的代理对象
    • Configuration、mybatis-spring
    • => 调用 SqlSession 接口的 T getMapper(Class type)
    • => 调用Configuration实例的 T getMapper(Class type, SqlSession sqlSession)
    • => 调用MapperRegistry实例的 T getMapper(Class type, SqlSession sqlSession)
    • => 在 MapperRegistry 中根据已注册的 MapperProxyFactory 返回mapperProxyFactory.newInstance(sqlSession) 的结果——代理对象
    • mybatis-plus,同上,但使用的是 MybatisConfiguration、MybatisMapperRegistry。

MapperRegistry、MapperProxyFactory、MapperProxy的联系

MapperRegistry 用来缓存 MapperProxyFactory,并根据它和SqlSession来生成Mapper对象。
以下是它的两个属性:

private final Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
  • knownMappers
    • key 是Mapper类。
    • value 是生成Mapper代理的工厂类。

MapperProxyFactory 使用MapperProxy生成 Mapper 代理对象。两个属性:

private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
  • mapperInterface:mapper 接口。
  • methodCache:初始时大小为0,后续调用到 MapperProxy 时,添加(如果缓存中没有)。
    • key 为 mapper 接口中定义的方法。
    • value 类型为MapperMethodInvoker,是 MapperProxy 中定义的接口,类似于 InvocationHandler。

MapperProxy

  • 相比 MapperProxyFactory,MapperProxy 多了一个SqlSession属性。
  • MapperProxy 实现了 InvocationHandler,用于生成Mapper代理对象,即调用Mapper接口中的方法,会调用MapperProxy中实现的 invoke 方法。
  • MapperProxy中 的 invoke 调用的是 MapperMethod 的 execute 方法。
  @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else {return cachedInvoker(method).invoke(proxy, method, args, sqlSession);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}}private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {try {return MapUtil.computeIfAbsent(methodCache, method, m -> {if (m.isDefault()) { //如果是 default 方法try {if (privateLookupInMethod == null) {return new DefaultMethodInvoker(getMethodHandleJava8(method));} else {return new DefaultMethodInvoker(getMethodHandleJava9(method));}} catch (IllegalAccessException | InstantiationException | InvocationTargetException| NoSuchMethodException e) {throw new RuntimeException(e);}} else {return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));}-});} catch (RuntimeException re) {Throwable cause = re.getCause();throw cause == null ? re : cause;}}

2、Mapper 中方法的调用:

  • 调用 Mapper 中的方法
    • => MapperProxy.invoke = > MapperMethod.execute
    • => 调用 sqlSession.selectXXX 方法,即:SqlSessionTemplate => DefaultSqlSession
  • 使用 Executor
    • Executor(由Configuration.newExecutor创建;实现之一的CachingExecutor是包装类,包含属性 Executor delegate,启用缓存则进行包装)
    • 执行 SimpleExecutor的方法(默认的Executor,调用StatementHandler,实现方法:doQuery、doUpdate、doQueryCursor):
    • 生成StatementHandler代理对象(由Configuration.newStatementHandler创建,处理SQL语句,预编译,设置参数)
  • 使用 StatementHandler 创建 Statement 并执行
    • BaseStatementHandler 构造器中设置了 ParameterHandler、ResultSetHandler 两个实例。由Configuration中的两个方法创建:Configuration.newParameterHandler、Configuration.newResultSetHandler
    • 调用 prepare 方法创建 Statement
    • 调用 parameterize 方法设置参数 => 调用ParameterHandler设置参数(设置编译参数,设置参数:CallableStatementHandler、PreparedStatementHandler 中调用)
    • 调用 query 方法 => 调用ResultSetHandler处理结果(处理查询结果,有三个方法)
  • 备注
    • TypeHandler(数据库类型和JavaBean类型映射处理)
    • JDBCStatement.PreparedStatement(最终用原生JDBC的API处理)

引用:
Mybatis的SqlSession运行原理
Mybatis源码学习(27)-Mybatis中的执行器Executor(一)
Mybatis源码学习(28)-Mybatis中的执行器BatchExecutor
Mybatis源码学习(29)-Mybatis中的执行器CachingExecutor


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部