Mybatis之是如何执行你的SQL的(SQL执行过程,参数解析过程,结果集封装过程)
Myabtis的SQL的执行是通过SqlSession。默认的实现类是DefalutSqlSession。通过源码可以发现,selectOne最终会调用selectList这个方法。
- @Override
- public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
- try {
//获取MappedStatement 通过id 到configuration里面- MappedStatement ms = configuration.getMappedStatement(statement);
- 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();
- }
- }
通过上面可以发现是通过Executor去执行查询。但是executor是个接口,是什么时候指定的用什么执行器呢。
因为SqlSession是通过SqlSessionFactory接口获取的,实现类是DefaultSqlSessionFactory
- private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
- Transaction tx = null;
- try {
- final Environment environment = configuration.getEnvironment();
- final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
- tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
- final Executor executor = configuration.newExecutor(tx, execType);
- 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();
- }
- }
- 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;
- }
可以看到默认的是SimpleExecutor;然后默认的是开启缓存的,所以最终应该是一个CachingExecutor,但是CachingExecutor有一个构造器参数是前面的执行器。
这是一种典型的装饰器设计模式
下面那行代码你现在只需要知道如果有Executor的拦截器,就会返回一个代理对象,在执行executor方法前,会执行拦截器。这是动态代理。
后面讲Myabtis拦截器原理的时候会详细介绍。
这下知道了是CachingExecotor,来看下CachingExecutor方法;
- public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
- BoundSql boundSql = ms.getBoundSql(parameterObject);
- CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
- return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
- }
① 先看是如何获取BoundSql 这个对象,包含了sql,params等信息。
- public BoundSql getBoundSql(Object parameterObject) {
- 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();
- }
- }
- }
可以发现从sqlSource中获取BoundSql
一,DynamicSqlSourcre
- public class DynamicSqlSource implements SqlSource {
- private Configuration configuration;
- private SqlNode rootSqlNode;
- public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
- this.configuration = configuration;
- this.rootSqlNode = rootSqlNode;
- }
- @Override
- public BoundSql getBoundSql(Object parameterObject) {
这一块的操作就是替换sql里面${}部分- DynamicContext context = new DynamicContext(configuration, parameterObject);
- 14 rootSqlNode.apply(context);
- SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
- Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
- SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
- BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
- for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
- boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
- }
- return boundSql;
- }
- }
来看下是如何替换sql的:
- public DynamicContext(Configuration configuration, Object parameterObject) {
- if (parameterObject != null && !(parameterObject instanceof Map)) {
//如果参数类型不是map则构造一个MetaObject; //todo 这一块干嘛的目前还不清楚,后面研究mybatis反射时候研究
//这个对象 保存着Configuration的那个几个factory 反射factory 驼峰Factory,创建对象factory- MetaObject metaObject = configuration.newMetaObject(parameterObject);
- bindings = new ContextMap(metaObject);
- } else {
- bindings = new ContextMap(null);
- }
- bindings.put(PARAMETER_OBJECT_KEY, parameterObject);//_paramter
- bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());
- }
rootSqlNode.apply实际上接口的方法,这是根据节点的类别去执行,我们正常的MixedSqlNode实际上就是SqlNode数组类型,
这里只拿TextSqlNode做例子来看:
- @Override
- public boolean apply(DynamicContext context) {
- GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
- context.appendSql(parser.parse(text));
- return true;
- }
看过上一篇的应该对这段有了解, 就是用具体解析类来解析节点内容来,parser获取${}中间变量的名字,然后BindingTokenParser去处理;
parser.parses就是把sql里面每个${}替换成相应的值的作用
- public BindingTokenParser(DynamicContext context, Pattern injectionFilter) {
- this.context = context;
- this.injectionFilter = injectionFilter;
- }
- @Override
- public String handleToken(String content) {
//从参数对象里面获取值返回- Object parameter = context.getBindings().get("_parameter");
- if (parameter == null) {
- context.getBindings().put("value", null);
//是不是基本类型- } else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
- context.getBindings().put("value", parameter);
- }
//获取到对应值,这一块很复杂,有时间在研究。- Object value = OgnlCache.getValue(content, context.getBindings());
- String srtValue = (value == null ? "" : String.valueOf(value)); // issue #274 return "" instead of "null"
- checkInjection(srtValue);
- return srtValue;
- }
- private void checkInjection(String value) {
- if (injectionFilter != null && !injectionFilter.matcher(value).matches()) {
- throw new ScriptingException("Invalid input. Please conform to regex" + injectionFilter.pattern());
- }
- }
- }
好了 到此为止 sql里面${}都已经替换成该有的值了,根据变量名获取Value这一块下回研究下在另外写篇文章。
然后看这段代码:
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
这一段也很重要 实际上是填充boundSql里面parameterMapping的
来看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);
- return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
- }
这一块代码应该很熟悉了吧, 实际上就是把#{}替换成? 同时记录下参数的类型等信息,因为逻辑前面有介绍,直接看ParameterMappingTokenHandler的方法
- public String handleToken(String content) {
//记录参数- parameterMappings.add(buildParameterMapping(content));
//替换成?- return "?";
- }
- private ParameterMapping buildParameterMapping(String content) {
- Map<String, String> propertiesMap = parseParameterMapping(content);
- String property = propertiesMap.get("property");
- Class<?> propertyType;
- if (metaParameters.hasGetter(property)) { // issue #448 get type from additional params
- propertyType = metaParameters.getGetterType(property);
- } else if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
- propertyType = parameterType;
- } else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) {
- propertyType = java.sql.ResultSet.class;
- } else if (property != null) {
- MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());
- if (metaClass.hasGetter(property)) {
- propertyType = metaClass.getGetterType(property);
- } else {
- propertyType = Object.class;
- }
- } else {
- propertyType = Object.class;
- }
- ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
- Class<?> javaType = propertyType;
设置每个参数类型等。- String typeHandlerAlias = null;
- for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
- String name = entry.getKey();
- String value = entry.getValue();
- if ("javaType".equals(name)) {
- javaType = resolveClass(value);
- builder.javaType(javaType);
- } else if ("jdbcType".equals(name)) {
- builder.jdbcType(resolveJdbcType(value));
- } else if ("mode".equals(name)) {
- builder.mode(resolveParameterMode(value));
- } else if ("numericScale".equals(name)) {
- builder.numericScale(Integer.valueOf(value));
- } else if ("resultMap".equals(name)) {
- builder.resultMapId(value);
- } else if ("typeHandler".equals(name)) {
- typeHandlerAlias = value;
- } else if ("jdbcTypeName".equals(name)) {
- builder.jdbcTypeName(value);
- } else if ("property".equals(name)) {
- // Do Nothing
- } else if ("expression".equals(name)) {
- throw new BuilderException("Expression based parameters are not supported yet");
- } else {
- throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}. Valid properties are " + parameterProperties);
- }
- }
- if (typeHandlerAlias != null) {
- builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
- }
- return builder.build();
- }
现在回过头开始看CachingExecutor的query方法了
- public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
- throws SQLException {
//这块就是mybatis的二级缓存- Cache cache = ms.getCache();
- if (cache != null) {
- flushCacheIfRequired(ms);
- if (ms.isUseCache() && resultHandler == null) {
- ensureNoOutParams(ms, parameterObject, boundSql);
- @SuppressWarnings("unchecked")
- List<E> list = (List<E>) tcm.getObject(cache, key);
- if (list == null) {
- list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
- tcm.putObject(cache, key, list); // issue #578 and #116
- }
- return list;
- }
- }
//最终调用的还是CachingExecutor里装饰的那个执行器- return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
- }
这个方法是所有执行器父类的BaseExecutor来实现的
- 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;
- }
//这里应该就是mybatis的一级缓存,直接看从数据库查询数据
- 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 {
//在子类中实现的 doQuery 查询出来结果放入一级缓存- 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;
- }
看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 = ms.getConfiguration();
//创建StatementHandler的代理对象,有的话返回代理对象,没有返回默认的RoutingStatmenthandler 典型的责任链模式- StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
- stmt = prepareStatement(handler, ms.getStatementLog());
- return handler.<E>query(stmt, resultHandler);
- } finally {
- closeStatement(stmt);
- }
- }
接下来看下是怎么创建合适的Statement对象的,
- private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
- Statement stmt;
- Connection connection = getConnection(statementLog);
- stmt = handler.prepare(connection);
- 5 handler.parameterize(stmt);//设置参数
- return stmt;
- }
RoutingStatmenthandler
- @Override
- public Statement prepare(Connection connection) throws SQLException {
- return delegate.prepare(connection);
- }
- @Override
- public void parameterize(Statement statement) throws SQLException {
- delegate.parameterize(statement);
- }
调用的都是装饰的statementHander ,delegate是在RoutingStatementHandler构造器初始化的;
- public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
- switch (ms.getStatementType()) {
- case STATEMENT:
- delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
- break;
- case PREPARED:
- delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
- break;
- case CALLABLE:
- delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
- break;
- default:
- throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
- }
- }
可以看出来是根据ms保存的,三张就是Statement的三种,我们直接看预编译的,PreparedStatementHandler
实际上一些公共方法在BaseStatementHandler实现了
- public Statement prepare(Connection connection) throws SQLException {
- ErrorContext.instance().sql(boundSql.getSql());
- Statement statement = null;
- try {
- statement = instantiateStatement(connection);
- setStatementTimeout(statement);
- 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);
- }
- }
instantiateStatement子类PreparedStatementHandler实现
- protected Statement instantiateStatement(Connection connection) throws SQLException {
- String sql = boundSql.getSql();
- 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() != null) {
- return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
- } else {
- return connection.prepareStatement(sql);
- }
- }
上面就是根据mappedStatement的resultType不同创建不同构造器的Statement;
下面来看下参数是怎么设置的。PreparedStatementHandler,但是handler是里面的paramterHandler是什么实现类呢?什么时候注入的呢?
- public void parameterize(Statement statement) throws SQLException {
- parameterHandler.setParameters((PreparedStatement) statement);
- }
来看下BaseStatementHandler的构造器
- protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
- this.configuration = mappedStatement.getConfiguration();
- this.executor = executor;
- this.mappedStatement = mappedStatement;
- this.rowBounds = rowBounds;
- this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
- this.objectFactory = configuration.getObjectFactory();
- if (boundSql == null) { // issue #435, get the key before calculating the statement
- generateKeys(parameterObject);
- boundSql = mappedStatement.getBoundSql(parameterObject);
- }
- this.boundSql = boundSql;
- //都说是相当于注册参数处理器,结果集处理器了。下面看默认的参数处理器是啥
- this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
- 18 this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
- }
- public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
//可以看出来就是从mappenStatement的语言注册器创建参数处理器。实际上就一个语言处理器。- ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
- parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
- return parameterHandler;
- }
默认的就是XMLLanguageDriver
- public class XMLLanguageDriver implements LanguageDriver {
- @Override
- public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
- return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
- }
接下来就看DefaultParameterHandler怎么实现setParameters()
- @Override
- 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 = parameterMapping.getJdbcType();
- if (value == null && jdbcType == null) {
//这里有bug 如果传入值为0 也没设置参数jdbctype 会报错,这块可以给根据javaType给默认的类型- jdbcType = configuration.getJdbcTypeForNull();
- }
- try {
- 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);
- }
- }
- }
- }
- }
这块就很简单了 根据每个参数JavaType jdbctype设设置。到此为止 prepareStatement的参数就都设置完了。
来看下 查询return handler.<E>query(stmt, resultHandler);
实际上也是PreparedStatementHandler实现的
- @Override
- public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
- PreparedStatement ps = (PreparedStatement) statement;
- ps.execute();
//执行就不说了,就看下面 使用结果处理器来处理结果集 返回一个List- return resultSetHandler.<E> handleResultSets(ps);
- }
resultSetHandler在父类构造器初始化的。看下默认的是什么吧
- public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
- ResultHandler resultHandler, BoundSql boundSql) {
- 3 ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
- resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
- return resultSetHandler;
- }
- public List<Object> handleResultSets(Statement stmt) throws SQLException {
- ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
- final List<Object> multipleResults = new ArrayList<Object>();
- int resultSetCount = 0;
//ResultSet的包装类ResultSet,同时获取数据库的MetaData数据,包括数据表列名、列的类型、类序号等- ResultSetWrapper rsw = getFirstResultSet(stmt);
- List<ResultMap> resultMaps = mappedStatement.getResultMaps();
- int resultMapCount = resultMaps.size();
- validateResultMapsCount(rsw, resultMapCount);
- while (rsw != null && resultMapCount > resultSetCount) {
- ResultMap resultMap = resultMaps.get(resultSetCount);
- 14 handleResultSet(rsw, resultMap, multipleResults, null);
- rsw = getNextResultSet(stmt);
- cleanUpAfterHandlingResultSet();
- resultSetCount++;
- }
- String[] resultSets = mappedStatement.getResulSets();
- 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);
- }
- private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
- try {
- if (parentMapping != null) {
- 4 handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
- } else {
- if (resultHandler == null) {
- DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
- 8 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());
- }
- }
- private 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<Object>();
- skipRows(rsw.getResultSet(), rowBounds);
- while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
- ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
- Object rowValue = getRowValue(rsw, discriminatedResultMap); //获取每一行的值
- storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
- }
- }
- private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
- final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//创建数据对象的类对象 //todo这一块好复杂,有时间但单独在分析。- Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
- if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
- final MetaObject metaObject = configuration.newMetaObject(resultObject);
- boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
- if (shouldApplyAutomaticMappings(resultMap, false)) {
//这一块就是为这个对象挨个赋值了- foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
- }
- foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
- foundValues = lazyLoader.size() > 0 || foundValues;
- resultObject = foundValues ? resultObject : null;
- return resultObject;
- }
- return resultObject;
- }
- private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
- List<UnMappedColumAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
- boolean foundValues = false;
- if (autoMapping.size() > 0) {
//遍历表的每一项 给对象赋值。- for (UnMappedColumAutoMapping mapping : autoMapping) {
//根据对应的java类型调用不同getResult获取值 如String, getString(); Int getInt()- final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
- // issue #377, call setter on nulls
- if (value != null || configuration.isCallSettersOnNulls()) {
- if (value != null || !mapping.primitive) {
- metaObject.setValue(mapping.property, value);
- }
- foundValues = true;
- }
- }
- }
- return foundValues;
- }
到此为止,整个过程结束,结果集封装理解不是特别多,还有就是其中一些细节要以后慢慢推敲。如果有的地方解释的不对的地方希望看到的能及时提出探讨,万分感谢
Mybatis之是如何执行你的SQL的(SQL执行过程,参数解析过程,结果集封装过程)的更多相关文章
- 原!!mybatis如何直接 执行传入的任意sql语句 并按照顺序取出查询的结果集
需求: 1.直接执行前端传来的任何sql语句,parameterType="String", 2.对于任何sql语句,其返回值类型无法用resultMap在xml文件里配置或者返回 ...
- mybatis下使用log4j打印sql语句和执行结果
转载自:https://www.cnblogs.com/jeevan/p/3493972.html 本来以为很简单的问题, 结果自己搞了半天还是不行; 然后google, baidu, 搜出来各种方法 ...
- [转]mybatis如何直接 执行传入的任意sql语句 并按照顺序取出查询的结果集
原文地址:https://www.cnblogs.com/wuyun-blog/p/5769096.html 需求: 1.直接执行前端传来的任何sql语句,parameterType="St ...
- mybatis如何直接 执行传入的任意sql语句 并按照顺序取出查询的结果集
需求: 1.直接执行前端传来的任何sql语句,parameterType="String", 2.对于任何sql语句,其返回值类型无法用resultMap在xml文件里配置或者返回 ...
- 初看Mybatis 源码 (三) SQL是怎么执行的
前面说到Java动态代理,Mybatis通过这种方式实现了我们通过getMapper方式得到的Dao接口,可以直接通过接口的没有实现的方法来执行sql. AuthUserDao mapper = se ...
- 【mybatis】service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据【事务的问题】
问题描述: service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据 ...
- 面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他
初识 MyBatis MyBatis 是第一个支持自定义 SQL.存储过程和高级映射的类持久框架.MyBatis 消除了大部分 JDBC 的样板代码.手动设置参数以及检索结果.MyBatis 能够支持 ...
- MyBatis学习(一)---配置文件,Mapper接口和动态SQL
MyBatis MyBatis官方学习网站 http://www.mybatis.org/mybatis-3/zh/index.html 为什么需要MyBatis? Jdbc操作数据库的不足之处 1. ...
- Java Persistence with MyBatis 3(中文版) 第三章 使用XML配置SQL映射器
关系型数据库和SQL是经受时间考验和验证的数据存储机制.和其他的ORM 框架如Hibernate不同,MyBatis鼓励开发者可以直接使用数据库,而不是将其对开发者隐藏,因为这样可以充分发挥数据库服务 ...
随机推荐
- WCF WS-Security and WSE Nonce Authentication【转】
原文:http://weblog.west-wind.com/posts/2012/Nov/24/WCF-WSSecurity-and-WSE-Nonce-Authentication?utm_sou ...
- 利用Web Services开发分布式应用
一.引言 在前面文章中分别介绍了MSMQ和.NET Remoting技术,今天继续分享.NET 平台下另一种分布式技术——Web Services 二.Web Services 详细介绍 2.1 We ...
- /etc/fstab和/etc/mtab
一./etc/fstab和/etc/mtab的区别 1./etc/fstab /etc/fstab是开机自动挂载的配置文件,在开机时起作用.相当于启动linux的时候,自动使用检查分区的fsck命令和 ...
- Spring Boot 报错:Error creating bean with name 'entityManagerFactory' defined in class path resource
spring boot 写一个web项目,在使用spring-data-jpa的时候,启动报如下错误: Error starting ApplicationContext. To display th ...
- Hive之 数据类型
hive 目前支持的数据类型如下: -- 数值类型 Numeric TypesTINYINT (1-byte signed integer, from -128 to 127)SMALLINT (2- ...
- docker默认配置文件不存在问题解决
Docker默认的配置文件/etc/default/docker或者/etc/sysconfig/docker都不起作用,查看了一下/lib/systemd/system/docker.service ...
- bzoj3143游走
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3143 学到了无向图中点被经过的期望次数和边被经过的期望次数. 一个点被经过的期望次数 就是 ...
- 【python】 使用 setuptools
不会安装python的egg文件,在网上搜索了一下,被“蟒蛇蛋”这个词雷到了,记录下. 随着对python的逐渐使用,发现一些python组件是用一个包管理器发布的,今天搞了快一个小时,终于搞定了,这 ...
- 安装memcached服务 和 php 安装memcache扩展
这是所有的命令,至于哪个命令是干嘛的自己悟去吧 ,顺便穿插一些知识点 安装libevent cd /home/ wget http://www.monkey.org/~provos/libeven ...
- Bootstrap-CL:面板
ylbtech-Bootstrap-CL:面板 1.返回顶部 1. Bootstrap 面板(Panels) 本章将讲解 Bootstrap 面板(Panels).面板组件用于把 DOM 组件插入到一 ...