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执行器对象 默认创建SimpleExecutorfinal 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()) {//返回值是一个Listresult = executeForMany(sqlSession, args);} else if (method.returnsMap()) {//返回值是一个mapresult = executeForMap(sqlSession, args);} else if (method.returnsCursor()) {//返回游标result = executeForCursor(sqlSession, args);} else {//查询返回单个// 解析我们的参数Object param = method.convertArgsToSqlCommandParam(args);// 通过调用DefaultSqlSession来执行我们的sqlresult = 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去我们的全局配置类中获取MappedStatementMappedStatement ms = configuration.getMappedStatement(statement);//2 通过执行器去执行我们的sql对象 默认实现:CachingExecutorreturn 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) {//去一级缓存获取 实现类:BaseExecutorlist = 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 #601deferredLoads.clear();if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {// issue #482clearLocalCache();}}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对象 默认是SimpleExecutorlist = 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 默认实现:PreparedStatementHandlerstmt = 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);
}