mybatis源码解析-sql执行流程
1 执行器的创建
1. SimpleExecutor
-
描述:最基本的执行器,每次查询都会创建新的语句对象,并且不会缓存任何结果。
-
特点:
-
每次查询都会创建新的 PreparedStatement 对象。
-
不支持一级缓存。
-
适用于简单的查询操作,不需要缓存的情况。
-
2. ReuseExecutor
-
描述:复用型执行器,会复用 PreparedStatements。
-
特点:
-
通过缓存 PreparedStatement 对象来提高性能。
-
支持一级缓存。
-
适用于多次执行相同的 SQL 语句,尤其是参数不同的情况。
-
3. BatchExecutor
-
描述:批量执行器,用于批量执行 SQL 语句。
-
特点:
-
支持批量插入和更新操作。
-
通过缓存 PreparedStatement 对象来提高性能。
-
将多个 SQL 语句打包在一起,减少数据库通信次数,提高性能。
-
适用于大数据量的批量操作。
-
需要手动调用
flushStatements
方法来提交批量操作。
-
执行语句如下:
SqlSession session = sqlSessionFactory.openSession();
核心类:DefaultSqlSessionFactory 执行方法:openSession
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//1 获取环境变量
final Environment environment = configuration.getEnvironment();
//2 获取事务工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//3 创建一个sql执行器对象 默认创建SimpleExecutor
final Executor executor = configuration.newExecutor(tx, execType);
//4 创建返回一个DefaultSqlSession对象返回
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();
}
}
2 代理对象的创建
语句如下
UserMapper mapper = session.getMapper(UserMapper.class);
源码解析
核心类:DefaultSqlSession 核心方法:getMapper
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//1 直接去缓存knownMappers中通过Mapper的class类型去找我们的mapperProxyFactory
//xml解析时 会把所有的mapper接口存放至这个map value是一个代理
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
//2 缓存中没有获取到 直接抛出异常
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//3 通过MapperProxyFactory来创建我们的实例
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
public T newInstance(SqlSession sqlSession) {
//1 创建我们的代理对象
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
//2 创建我们的Mapper代理对象返回
return newInstance(mapperProxy);
}
//JDK代理生成对象
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
3 sql的执行
执行语句:
User user = mapper.selectById(1);
执行这条语句时,由于mapper是一个代理对象,会自动执行创建代理对象中构造函数的InvocationHandler中invoke方法,这里mybatis包装了InvocationHandler对象,自定义了一个类继承InvocationHandler。
核心类:MapperProxy 核心方法:invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//1 判断我们的方法是不是我们的Object类定义的方法,若是直接通过反射调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (method.isDefault()) {
//是否接口的默认方法
//2 调用我们的接口中的默认方法
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//3 真正的进行调用,做了二个事情
//第一步:把我们的方法对象封装成一个MapperMethod对象(带有缓存作用的)
final MapperMethod mapperMethod = cachedMapperMethod(method);
//4 通过sqlSessionTemplate来调用我们的目标方法
return mapperMethod.execute(sqlSession, args);
}
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
//1 判断我们执行sql命令的类型
switch (command.getType()) {
//insert操作
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
//update操作
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
//delete操作
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
//select操作
case SELECT:
//返回值为空
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
//返回值是一个List
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);
// 通过调用DefaultSqlSession来执行我们的sql
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.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;
}
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
//1 这里selectOne调用也是调用selectList方法
List<T> list = this.selectList(statement, parameter);
//2 若查询出来有且有一个一个对象,直接返回要给
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;
}
}
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//1 第一步:通过我们的statement去我们的全局配置类中获取MappedStatement
MappedStatement ms = configuration.getMappedStatement(statement);
//2 通过执行器去执行我们的sql对象 默认实现:CachingExecutor
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();
}
}
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
/**
* 判断我们我们的mapper中是否开启了二级缓存<cache></cache>
*/
Cache cache = ms.getCache();
/**
* 判断是否配置了<cache></cache>
*/
if (cache != null) {
//判断是否需要刷新缓存
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
/**
* 先去二级缓存中获取
*/
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
/**
* 二级缓存中没有获取到
*/
if (list == null) {
//去一级缓存获取 实现类:BaseExecutor
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
//加入到二级缓存中
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
//没有整合二级缓存,直接去查询
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
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());
//1 已经关闭,则抛出 ExecutorException 异常
if (closed) {
throw new ExecutorException("Executor was closed.");
}
//2 清空本地缓存,如果 queryStack 为零,并且要求清空本地缓存。
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
//3 从一级缓存中,获取查询结果
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
//4 获取到,则进行处理
if (list != null) {
//5 处理存过的
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//6 获得不到,则从数据库中查询
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
//选择配置的执行器执行sql对象 默认是SimpleExecutor
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
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();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//1 拿到连接 预处理语句statement 默认实现:PreparedStatementHandler
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
//1 执行sql语句
ps.execute();
//2 处理返回结果
return resultSetHandler.handleResultSets(ps);
}