赞
踩
上回我们分析了Mybatis解析mapper映射文件的代码,我们继续上次的分析,开始mybatis执行sql语句的流程,话不多说咱们上代码!!!!!!
上回我们分析了mybatis解析mapper映射文件的过程
mapper
标签;select|insert|update|delete
标签;SqlSource
;builderAssistant
(构建者助手),构建MappedStatement
对象;MappedStatement
对象放入configuration
对象中的mappedStatements
map中;最终我们的到SqlSessionFactory
对象,封装后具体结构如下:
回到我们的main方法中,得到SqlSessionFactory
对象后,调用sqlSessionFactory.openSession()
方法创建SqlSession对象;
//通过工厂生产一个sqlsession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //调用sqlSessionFactory的openSession方法 @Override public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // 获取数据源环境信息 final Environment environment = configuration.getEnvironment(); // 获取事务工厂 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); // 获取JdbcTransaction或者ManagedTransaction tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 创建Executor执行器 final Executor executor = configuration.newExecutor(tx, execType); // 创建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(); } }
获取事务工厂创建TransactionFactory
(我们使用的是jdbc,所以创建的是JdbcTransactionFactory,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交),通过工厂创建Transaction(我们使用的是jdbc,所以创建的是JdbcTransaction);创建Executor执行器,用来操作数据库;
//Executor执行器 public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { // 批处理执行器 executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { // 可重用执行器 executor = new ReuseExecutor(this, transaction); } else { // 简单执行器 executor = new SimpleExecutor(this, transaction); } // 如果开启缓存(默认是开启的),则使用缓存执行器 if (cacheEnabled) { executor = new CachingExecutor(executor); } // 插件执行 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
我们这里创建了一个简单执行器,mybatis默认是开启了一级缓存的,又创建缓存执行器,后面用来执行我们解析好的sql语句,最后创建了一个DefaultSqlSession对象;
通过SqlSession获取接口的代理对象
//通过SqlSession获取一个PersionMapper接口的代理对象 PersonMapper mapper = sqlSession.getMapper(PersonMapper.class); //调用Sqlsession的getMapper调用configuration中的getMapper方法 public <T> T getMapper(Class<T> type) { // 从Configuration对象中,根据Mapper接口,获取Mapper代理对象 return configuration.<T>getMapper(type, this); } //从configuration中取到之前封装好的mapperRegistry //里面有之前放进去的代理对象工厂 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); } //调用mapperRegistry的getMapper方法取到Mapper代理对象工厂 //key为接口的class对象,value为接口的代理对象工厂 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { // 根据Mapper接口的类型,从Map集合中获取Mapper代理对象工厂 final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { // 通过MapperProxyFactory生产MapperProxy,通过MapperProxy产生Mapper代理对象 return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
从mapperRegistry
中取到mapper的代理对象工厂,并生产MapperProxy
,通过MapperProxy
产生Mapper代理对象;
// 通过MapperProxyFactory生产MapperProxy,通过MapperProxy产生Mapper代理对象
return mapperProxyFactory.newInstance(sqlSession);
//调用生产出来的mapperProxyFactory的newInstance方法,生产mapperProxy
public T newInstance(SqlSession sqlSession) {
// 创建基于JDK实现的Mapper代理对象
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
//通过mapperProxy创建Mapper接口代理对象
protected T newInstance(MapperProxy<T> mapperProxy) {
// 使用JDK动态代理方式,生成代理对象
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
这里通过MapperProxyFactory
生产了一个MapperProxy
对象,通过MapperProxy
给予JDK的动态代理创建了一个mapper代理对象;
执行代理对象的seleceById方法
//创建入参对象并赋值 Person person1 = new Person(); person1.setId("1"); //执行selectById方法传入入参 "1" Person person = mapper.selectById(person1); // public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // 是Interface接口还是Object类 // 如果方法是Object类自带的方法,比如没有被重写的 equals toString, hashcode 等,还是执行原来的方法 // getDeclaringClass()返回表示声明由此 Method 对象表示的方法的类或接口的 Class 对象。 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else if (isDefaultMethod(method)) { return invokeDefaultMethod(proxy, method, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } // 如果不是object的自带方法,先去 Map<Method, MapperMethod> methodCache中找是否已经存在这个method了 // 没有就将method封装成MapperMethod存进mehtodCache中然后返回MapperMethod final MapperMethod mapperMethod = cachedMapperMethod(method); // 然后执行MapprMehtod的execute方法(执行sqlsession的方法) return mapperMethod.execute(sqlSession, args); }
执行代理对象的seleceById方法,会进入MapperProxy.invoke()方法,判断当前是Interface接口还是Object类,判断有没有缓存这个方法,最后执行MapperProxy.execute()方法;
执行MapperProxy.execute()方法
//执行MapperProxy.execute()执行SQL脚本,得到结果对象,然后转换成对应method返回类型的对象 public Object execute(SqlSession sqlSession, Object[] args) { Object result; //判断Sql指令类型 switch (command.getType()) { //插入指令 case INSERT: { //构建sql脚本参数名-参数对象映射集合; Object param = method.convertArgsToSqlCommandParam(args); //执行插入Sql脚本,然后将更新记录数转换成method所需要的返回类型对象 result = rowCountResult(sqlSession.insert(command.getName(), param)); break; } //修改指令 case UPDATE: { //构建sql脚本参数名-参数对象映射集合; Object param = method.convertArgsToSqlCommandParam(args); //执行修改Sql脚本,然后将更新记录数转换成method所需要的返回类型对象 result = rowCountResult(sqlSession.update(command.getName(), param)); break; } //删除指令 case DELETE: { //构建sql脚本参数名-参数对象映射集合; Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); break; } //查询指令 case SELECT: //如果method返回类型为void 而且 method有ResultHandler类型参数 if (method.returnsVoid() && method.hasResultHandler()) { //用ResultHandler执行查询sql executeWithResultHandler(sqlSession, args); //处理结果赋值为ull result = null; //如果method返回类型为Collection的子类或者返回类型是数组 } else if (method.returnsMany()) { /** * 执行查询SQL,默认返回结果对象集合,但如果method返回类型为数组,该方法就会自动将结果对象集合 * 转换成数组;如果method返回类型为自定义的Collection实现类,该方法也会将结果对象集合的元素添加到 * 自定义的Collection实现类对象中 */ result = executeForMany(sqlSession, args); //如果method的返回类型是Map } else if (method.returnsMap()) { //执行查询SQL,返回结果对象映射赋值给result result = executeForMap(sqlSession, args); //如果method返回类型是Cursor游标 } else if (method.returnsCursor()) { //执行查询SQL,返回结果对象游标赋值给result result = executeForCursor(sqlSession, args); } else { //构建sql脚本参数名-参数对象映射集合 Object param = method.convertArgsToSqlCommandParam(args); //执行查询SQL,返回结果对象赋值给result result = sqlSession.selectOne(command.getName(), param); //如果method返回类型为Optional 且 结果对象为null 或者 method返回类型不等于结果对象类型 if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) { //如果对象即可能是 null 也可能是非 null,使用 ofNullable() 方法可以防止空指针异常 result = Optional.ofNullable(result); } } break; //刷新指令 case FLUSH: //执行全部等待批处理语句,并将结果封装到BatchResult集合中,然后赋值reuslt result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + command.getName()); } //如果结果对象为null 且 method的返回类型为原始类型 且 method的返回类型不是void 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; }
执行SqlSession.selectOne()方法
//执行查询SQL,返回结果对象赋值给result result = sqlSession.selectOne(command.getName(), param); //执行SqlSession的selectOne方法 public <T> T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. List<T> list = this.selectList(statement, parameter); 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; } } //执行SqlSession的selectList public <E> List<E> selectList(String statement, Object parameter) { return this.selectList(statement, parameter, RowBounds.DEFAULT); } //执行selectList方法 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { // 根据传入的statementId,获取MappedStatement对象 MappedStatement ms = configuration.getMappedStatement(statement); // 调用执行器的查询方法 // RowBounds是用来逻辑分页(按照条件将数据从数据库查询到内存中,在内存中进行分页) // wrapCollection(parameter)是用来装饰集合或者数组参数 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(); } }
根据statementId
在configuration中取到对应的MappedStatement对象,调用执行器执行查询方法;
//调用之前创建的CachingExecutor的query方法 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { // 获取绑定的SQL语句,比如“SELECT * FROM user WHERE id = ? ” BoundSql boundSql = ms.getBoundSql(parameterObject); // 生成缓存Key CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); } //调用MappedStatement.getBoundSql()获取绑定的SQL语句 public BoundSql getBoundSql(Object parameterObject) { // 调用SqlSource获取BoundSql BoundSql boundSql = sqlSource.getBoundSql(parameterObject); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings == null || parameterMappings.isEmpty()) { boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject); } // check for nested result maps in parameter mappings (issue #30) for (ParameterMapping pm : boundSql.getParameterMappings()) { String rmId = pm.getResultMapId(); if (rmId != null) { ResultMap rm = configuration.getResultMap(rmId); if (rm != null) { hasNestedResultMaps |= rm.hasNestedResultMaps(); } } } return boundSql; } //调用SqlSource获取BoundSql public BoundSql getBoundSql(Object parameterObject) { //创建动态sql上下文 DynamicContext context = new DynamicContext(configuration, parameterObject); // 此处会调用MixedSqlNode中包含的所有SqlNode的apply方法 // 此处会处理${},也会处理动态标签 // 最终将所有的SqlNode信息进行解析之后,追加到DynamicContext对象的StringBuilder对象中 rootSqlNode.apply(context); // 创建SQL信息解析器 SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); // 获取入参类型 Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); // 执行解析:将带有#{}的SQL语句进行解析,然后封装到StaticSqlSource中 SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings()); // 将解析后的SQL语句还有入参绑定到一起(封装到一个对象中,此时还没有将参数替换到SQL占位符?) BoundSql boundSql = sqlSource.getBoundSql(parameterObject); for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) { boundSql.setAdditionalParameter(entry.getKey(), entry.getValue()); } return boundSql; }
创建动态SQL上下文,执行SqlSource中封装的rootSqlNode的apply方法,处理${}、处理动态标签,将处理过后的sql追加到动态SQL上下文中的StringBuilder对象中;
这里详细讲解一下每个SqlNode:
SQLNode:每个Xml Node都会解析成对应的SQLNode对象
//SqlNode接口 public interface SqlNode { //将各个Sql片段合并到DynamicContext中,拼接为完整的SQL; boolean apply(DynamicContext context); } //MixedSqlNode public class MixedSqlNode implements SqlNode { //记录sql节点中的所有SQL片段 private final List<SqlNode> contents; public MixedSqlNode(List<SqlNode> contents) { this.contents = contents; } @Override public boolean apply(DynamicContext context) { for (SqlNode sqlNode : contents) { sqlNode.apply(context); } return true; } }
通过解析Sql节点得到的MixedSqlNode结构如下:
StaticSqlSource:最简单的SqlNode,功能仅仅是将自身记录的text拼接到context上下文中;
//StaticTextSqlNode
public class StaticTextSqlNode implements SqlNode {
private final String text;
public StaticTextSqlNode(String text) {
this.text = text;
}
@Override
public boolean apply(DynamicContext context) {
context.appendSql(text);
return true;
}
}
TextSqlNode:表示包含‘${}’占位符的动态Sql节点;
//使用GenericTokenParser解析‘${}’,并直接转换成传入的实际参数 public boolean apply(DynamicContext context) { GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter)); context.appendSql(parser.parse(text)); return true; } //实际参数值获取逻辑方法 @Override public String handleToken(String content) { // 获取入参对象 Object parameter = context.getBindings().get("_parameter"); // 如果入参对象为null或者入参对象是简单类型,不需要关注${}中的名称,直接设置${}的参数名称必须为value // 如果content不为value,则取不出数据,会报错 if (parameter == null) { // context.getBindings().put("value", null); return ""; } else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) { // context.getBindings().put("value", parameter); return String.valueOf(parameter); } // 使用Ognl API,通过content中的表达式去获取入参对象中的指定属性值 // context.getBindings()就是一个ContextMap对象,也是HashMap的子对象 Object value = OgnlCache.getValue(content, parameter); String srtValue = value == null ? "" : String.valueOf(value); // issue #274 return "" instead of "null" checkInjection(srtValue); return srtValue; }
IFSqlNode:if标签平常使用的是最多的,在处理对应的逻辑节点时,主要工作就是通过Ognl表达式和传入的参数进行判断,看传入的参数是否满足if test里的表达式,满足将SQL片段合并到context上下文中。若不满足test则过滤掉这一部分的SQL片段,不添加到context中;
@Override
public boolean apply(DynamicContext context) {
//通过Ognl表达式和传入的参数进行判断,看传入的参数是否满足if test里的表达式
if (evaluator.evaluateBoolean(test, context.getBindings())) {
contents.apply(context);
return true;
}
return false;
}
WhereSqlNode和SetSqlNode:都是继承自TrimSqlNode
prefix=WHERE
和 prefixesToOverride=["AND ","OR ","AND\n", "OR\n", "AND\r", "OR\r", "AND\t", "OR\t"]
;prefix=WHERE
和prefixesToOverride=[“,”]
;prefix=WHERE
和prefixesToOverride=[“,”]
;TrimSqlNode:<trim /> 标签的SqlNode实现类;
ForEachSqlNode:<foreach /> 标签的SqlNode实现类;
VarDeclSqlNode: <bind /> 标签的SqlNode实现类;
最后动态sql上下文中拼接好的sql为:
解析’#{}’
//创建SqlSourceBuilder解析#{}
public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType,
additionalParameters);
// 创建分词解析器
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
// 解析#{}
String sql = parser.parse(originalSql);
// 将解析之后的SQL信息,封装到StaticSqlSource对象中
// SQL字符串是带有?号的字符串,?相关的参数信息,封装到ParameterMapping集合中
return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
}
调用缓存执行器的query方法;
@Override public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { // 获取二级缓存 Cache cache = ms.getCache(); 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; } } // 委托给BaseExecutor执行 return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
这里查看是否存在二级缓存,如果存在则查询二级缓存,不存在则查询数据库(前提是开启了mybatis的二级缓存)
委托给BaseExecutor执行查询方法
@Override 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()); if (closed) { throw new ExecutorException("Executor was closed."); } if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { queryStack++; // 从一级缓存中获取数据 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { // 如果一级缓存没有数据,则从数据库查询数据 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; }
查看一级缓存是否有数据,没有的话则从数据库查询;
调用BaseExecutor.queryFromDatabase()方法
//调用BaseExecutor.queryFromDatabase()方法 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; //将缓存key存入一级缓存中 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; }
将处理好的sql,以及查询结果存入一级缓存中,执行查询方法;
执行SimpleExecutor的查询方法doQuery
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { // 获取Configuration对象 Configuration configuration = ms.getConfiguration(); // 创建RoutingStatementHandler,用来处理Statement // RoutingStatementHandler类中初始化delegate类(SimpleStatementHandler、PreparedStatementHandler) StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); // 子流程1:设置参数 stmt = prepareStatement(handler, ms.getStatementLog()); // 子流程2:执行SQL语句(已经设置过参数),并且映射结果集 return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } }
创建RoutingStatementHandler用来处理对应的Statement,构造方法如下;
//根据不同的类型创建不同的Statement处理器,进行处理 public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { switch (ms.getStatementType()) { //简单的Statement处理器 case STATEMENT: delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; //PreparedStatement处理器 case PREPARED: delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; //callable处理器 case CALLABLE: delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; default: throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); } }
根据不同的类型创建不同的Statement处理器,处理statement;
//后获取jdbc链接,创建Statement并设置Statement参数 private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; // 获取连接 Connection connection = getConnection(statementLog); // 创建Statement(PreparedStatement、Statement、CallableStatement) stmt = handler.prepare(connection, transaction.getTimeout()); // SQL参数设置 handler.parameterize(stmt); return stmt; } //创建prepareStatement public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(boundSql.getSql()); Statement statement = null; try { // 实例化Statement,比如PreparedStatement statement = instantiateStatement(connection); // 设置查询超时时间 setStatementTimeout(statement, transactionTimeout); setFetchSize(statement); return statement; } catch (SQLException e) { closeStatement(statement); throw e; } catch (Exception e) { closeStatement(statement); throw new ExecutorException("Error preparing statement. Cause: " + e, e); } } //创建prepareStatement protected Statement instantiateStatement(Connection connection) throws SQLException { // 获取带有占位符的SQL语句 String sql = boundSql.getSql(); // 处理带有主键返回的SQL if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { String[] keyColumnNames = mappedStatement.getKeyColumns(); if (keyColumnNames == null) { return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); } else { return connection.prepareStatement(sql, keyColumnNames); } } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) { return connection.prepareStatement(sql); } else { return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } } //调用prepareStatement的parameterize方法,使用parameterHandler参数处理器设置参数 public void parameterize(Statement statement) throws SQLException { // 通过ParameterHandler处理参数 parameterHandler.setParameters((PreparedStatement) statement); } //对prepareStatement设置参数 public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); // 获取要设置的参数映射信息 List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); // 只处理入参 if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; // 获取属性名称 String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } // 获取每个参数的类型处理器,去设置入参和获取返回值 TypeHandler typeHandler = parameterMapping.getTypeHandler(); // 获取每个参数的JdbcType JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { // 给PreparedStatement设置参数 typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException e) { throw new TypeException( "Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } catch (SQLException e) { throw new TypeException( "Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
在参数处理器中创建每个参数的typeHandler(类型处理器的)setParameter方法,设置参数;
执行StatementHandler的query方法执行sql语句
//执行PreparedStatement,也就是执行SQL语句
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 执行PreparedStatement,也就是执行SQL语句
ps.execute();
// 处理结果集
return resultSetHandler.handleResultSets(ps);
}
处理结果集
public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); // <select>标签的resultMap属性,可以指定多个值,多个值之间用逗号(,)分割 final List<Object> multipleResults = new ArrayList<>(); int resultSetCount = 0; // 这里是获取第一个结果集,将传统JDBC的ResultSet包装成一个包含结果列元信息的ResultSetWrapper对象 ResultSetWrapper rsw = getFirstResultSet(stmt); // 这里是获取所有要映射的ResultMap(按照逗号分割出来的) List<ResultMap> resultMaps = mappedStatement.getResultMaps(); // 要映射的ResultMap的数量 int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); // 循环处理每个ResultMap,从第一个开始处理 while (rsw != null && resultMapCount > resultSetCount) { // 得到结果映射信息 ResultMap resultMap = resultMaps.get(resultSetCount); // 处理结果集 // 从rsw结果集参数中获取查询结果,再根据resultMap映射信息,将查询结果映射到multipleResults中 handleResultSet(rsw, resultMap, multipleResults, null); rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } // 对应<select>标签的resultSets属性,一般不使用该属性 String[] resultSets = mappedStatement.getResultSets(); if (resultSets != null) { while (rsw != null && resultSetCount < resultSets.length) { ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]); if (parentMapping != null) { String nestedResultMapId = parentMapping.getNestedResultMapId(); ResultMap resultMap = configuration.getResultMap(nestedResultMapId); handleResultSet(rsw, resultMap, null, parentMapping); } rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } } // 如果只有一个结果集合,则直接从多结果集中取出第一个 return collapseSingleResultList(multipleResults); } //调用上边的handleResultSet(rsw, resultMap, multipleResults, null); //处理结果映射 private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException { try { // 处理嵌套结果映射 if (parentMapping != null) { handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping); } else { // 第一次一般来说resultHandler为空,则创建DefaultResultHandler来处理结果 if (resultHandler == null) { DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory); // 处理行数据,其实就是完成结果映射 handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); multipleResults.add(defaultResultHandler.getResultList()); } else { handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); } } } finally { // issue #228 (close resultsets) closeResultSet(rsw.getResultSet()); } } //判断映射嵌套关系 public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { // 是否有内置嵌套的结果映射 if (resultMap.hasNestedResultMaps()) { ensureNoRowBounds(); checkResultHandler(); // 嵌套结果映射 handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } else { // 简单结果映射 handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } } //处理简单的映射关系 private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { DefaultResultContext<Object> resultContext = new DefaultResultContext<>(); // 获取结果集信息 ResultSet resultSet = rsw.getResultSet(); // 使用rowBounds的分页信息,进行逻辑分页(也就是在内存中分页) skipRows(resultSet, rowBounds); while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) { // 通过<resultMap>标签的子标签<discriminator>对结果映射进行鉴别 ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null); // 将查询结果封装到POJO中 Object rowValue = getRowValue(rsw, discriminatedResultMap, null); // 处理对象嵌套的映射关系 storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); } }
处理完成后,将查询到的结果返回;
到这里我们完整的走了一遍Mybatis通过接口Mapper映射文件查询数据库,经过了解析xml、封装SQl、获取SQl、执行SQl、解析结果集。希望通过学习源码让自己对框架的了解更深一些.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。