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> T getMapper(Class<T> type)
- => 调用Configuration实例的 <T> T getMapper(Class<T> type, SqlSession sqlSession)
- => 调用MapperRegistry实例的 <T> T getMapper(Class<T> type, SqlSession sqlSession)
- => 在 MapperRegistry 中根据已注册的 MapperProxyFactory 返回mapperProxyFactory.newInstance(sqlSession) 的结果——代理对象
- mybatis-plus,同上,但使用的是 MybatisConfiguration、MybatisMapperRegistry。
MapperRegistry、MapperProxyFactory<T>、MapperProxy<T>的联系
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 方法。
@Override
public 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处理)