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语句,预编译,设置参数)
- Executor(由Configuration.newExecutor创建;实现之一的
- 使用 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
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
