传统的JDBC编程中的一般操作:
ORM(Object Relational Mapping) 对象—关系映射。用于实现面向对象编程语言里 不同类型系统的数据 之间的转换。
经过多次追踪、找到这个getResourceAsStream
核心方法,以下是该方法的源码
该方法的参数不仅有传入的文件路径还有类加载器。类加载的主要作用是将名称转化为文件名,读取外部资源。
作为debug的入口
跟踪到核心源码部分
这里完成两个操纵:
先追踪XMLConfigBuilder对象的parse()方法
这里的parsed保证只加载一次,这里的/configuration
是整个配置文件的根节点、是解析整个配置文件的入口。然后调用parseConfiguration
方法,继续追踪
查看root的传入的值,实际上就是configuration下的各个节点
<configuration> <typeAliases> <package name="com.github.yeecode.mybatisdemo"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/github/yeecode/mybatisdemo/UserMapper.xml"/> </mappers> </configuration>
查看environment下的信息、继续追踪,到environmentsElement
方法,
查看传入的context的值,这里就是解析的信息。也就是url、username、password 、驱动的信息。和上一个的信息是不一样的
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments>
通过进入每个子方法可以看出来,Configuration类中保存了配置文件的所有配置信息。
通过调用SqlSessionFactoryBuilder自身的build()方法,返回了SqlSessionFactory
对象。
小结
初始化阶段、MyBatis主要完成以下几项工作
追踪openSession方法
进入openSessionFromDataSource
方法内部,这里是生成SqlSession的核心源码
进入DefaultSqlSession
类中,类里提供了查询、增加、更新、删除、提交、回滚等大量的方法
执行完new DefaultSqlSession(this.configuration, executor, autoCommit);
后就返回了一个SqlSession对象
通过操作Configuration
的getMapper方法最终进入MapperRegistry
类的getMapper
方法。
session.getMapper(UserMapper.class)
得到的是mapperProxyFactory.newInstance(sqlSession)
返回的对象,追踪此方法得到
返回的是基于反射的动态代理对象,找到MapperProxy类的invoke方法,被代理对象的方法会被代理对象的invoke方法拦截、直接到 MapperProxy
类的invoke方法拦截,
在invoke打上断点,当执行userMapper.queryUserBySchoolName(userParam);
会自动进入断点invoke内
然后会触发MapperMethod对象的execute方法
进入该方法
public Object execute(SqlSession sqlSession, Object[] args) { Object result; Object param; switch(this.command.getType()) { case INSERT: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.insert(this.command.getName(), param)); break; case UPDATE: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.update(this.command.getName(), param)); break; case DELETE: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.delete(this.command.getName(), param)); break; case SELECT: if (this.method.returnsVoid() && this.method.hasResultHandler()) { this.executeWithResultHandler(sqlSession, args); result = null; } else if (this.method.returnsMany()) { result = this.executeForMany(sqlSession, args); } else if (this.method.returnsMap()) { result = this.executeForMap(sqlSession, args); } else if (this.method.returnsCursor()) { result = this.executeForCursor(sqlSession, args); } else { param = this.method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(this.command.getName(), param); if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) { result = Optional.ofNullable(result); } } break; case FLUSH: result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + this.command.getName()); } if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) { throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ")."); } else { return result; } }
会根据不同的操作类型调用不同的处理方法、这里执行的是查询操作、所以就调用这个方法
进入executeForMany
方法,在这个方法中,MyBatis已经开始通过SqlSession对象的selectList方法开展后续的查询工作。
继续追踪到DefaultSqlSession
中的selectList方法,源码如下
每个MappedStatement
对象对应设置的一个数据库操作节点,主要定义了数据库操作语句、输入/输出参数等信息。this.configuration.getMappedStatement(statement)
语句将要执行的MappedStatement
对象从Configuration对象存储的映射文件信息中找了出来。
其中的query
方法是Executor
中的抽象方法,实现有两个、一个是查询数据库、一个是查询缓存
直接在抽象方法上打一个断点、查看执行哪边、这里执行的是CachingExecutor
中的方法、源码如下
其中的BoundSql
是经过层层转化后去掉if、where、等标签的sql语句,CacheKey
是为该此次查询操作计算出来的缓存建。
继续追踪代码流程到这里
查看当前的查询操作是否名中缓存,如果是从缓存中获取数据值、如果不是则调用delegate调用query方法。随后将此次查询的结果放入缓存中。
再次调用了executor接口中的抽象方法
继续追踪代码流向
最终进入了BaseExecutor
中的query方法上,源码如下
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 (this.closed) { throw new ExecutorException("Executor was closed."); } else { if (this.queryStack == 0 && ms.isFlushCacheRequired()) { this.clearLocalCache(); } List list; try { ++this.queryStack; list = resultHandler == null ? (List)this.localCache.getObject(key) : null; if (list != null) { this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { --this.queryStack; } if (this.queryStack == 0) { Iterator var8 = this.deferredLoads.iterator(); while(var8.hasNext()) { BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next(); deferredLoad.load(); } this.deferredLoads.clear(); if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { this.clearLocalCache(); } } return list; } }
其中的关键部分、开始调用数据库展开查询操作
queryFromDatabase
的源代码如下
首先在缓存中放置一个占位符,然后调用doQuery方法实际执行,最后,将缓存中的占位符替换成真正的查询结果。
doQuery方法是BaseExecutor中的抽象方法,实际运行的最终实现代码
生成了Statement对象,是java.sql包中的类,Statement类能够执行静态SQL语句并返回结果。
获得了一个StatementHandler
对象handler,然后将查询操作交给StatementHandler
执行,StatementHandler
是一个语句处理器,其中封装了很多的语句操作方法。,继续追踪代码流向。
handler.query(stmt,resultHandler)调用的是StatementHandler接口中的抽象方法
接续追踪代码走向、进入PreparedStatementHandler中,调用方法、源码如下
这里,ps.execute()
真正执行了SQL语句,然后把执行结果交给ResulHandler对象处理。
流程梳理
查询到的结果集并没有直接返回,而是交给ResultHandler对象处理,ResultHandler是结果处理器,用来接受查询结果的方法是该接口中的抽象方法handleResultSets
继续代码追踪,最终的执行方法是DefaultResultSetHandler
类中的handleResultSets
方法
public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId()); List<Object> multipleResults = new ArrayList(); int resultSetCount = 0; ResultSetWrapper rsw = this.getFirstResultSet(stmt); List<ResultMap> resultMaps = this.mappedStatement.getResultMaps(); int resultMapCount = resultMaps.size(); this.validateResultMapsCount(rsw, resultMapCount); while(rsw != null && resultMapCount > resultSetCount) { ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount); this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null); rsw = this.getNextResultSet(stmt); this.cleanUpAfterHandlingResultSet(); ++resultSetCount; } String[] resultSets = this.mappedStatement.getResultSets(); if (resultSets != null) { while(rsw != null && resultSetCount < resultSets.length) { ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]); if (parentMapping != null) { String nestedResultMapId = parentMapping.getNestedResultMapId(); ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId); this.handleResultSet(rsw, resultMap, (List)null, parentMapping); } rsw = this.getNextResultSet(stmt); this.cleanUpAfterHandlingResultSet(); ++resultSetCount; } } return this.collapseSingleResultList(multipleResults); }
查询出来的结果被遍历后放入list列表multipleResults中并返回。
继续代码追踪
createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
方法:在自动属性映射功能开启的情况下,该方法将数据记录的值赋给输出结果对象。applyAutomaticMappings
方法private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException { List<DefaultResultSetHandler.UnMappedColumnAutoMapping> autoMapping = this.createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix); boolean foundValues = false; if (!autoMapping.isEmpty()) { Iterator var7 = autoMapping.iterator(); while(true) { DefaultResultSetHandler.UnMappedColumnAutoMapping mapping; Object value; do { if (!var7.hasNext()) { return foundValues; } mapping = (DefaultResultSetHandler.UnMappedColumnAutoMapping)var7.next(); value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column); if (value != null) { foundValues = true; } } while(value == null && (!this.configuration.isCallSettersOnNulls() || mapping.primitive)); metaObject.setValue(mapping.property, value); } } else { return foundValues; } }
applyAutomaticMappings
方法:该方法将按照用户的映射设置,给输出结果对象的属性赋值继续追踪代码、进入applyPropertyMappings
方法
private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix); boolean foundValues = false; List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings(); Iterator var9 = propertyMappings.iterator(); while(true) { while(true) { Object value; String property; do { ResultMapping propertyMapping; String column; do { if (!var9.hasNext()) { return foundValues; } propertyMapping = (ResultMapping)var9.next(); column = this.prependPrefix(propertyMapping.getColumn(), columnPrefix); if (propertyMapping.getNestedResultMapId() != null) { column = null; } } while(!propertyMapping.isCompositeResult() && (column == null || !mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) && propertyMapping.getResultSet() == null); value = this.getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix); property = propertyMapping.getProperty(); } while(property == null); if (value == DEFERRED) { foundValues = true; } else { if (value != null) { foundValues = true; } if (value != null || this.configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive()) { metaObject.setValue(property, value); } } } } }
执行完之后,装载着multipleResults被返回给List<User> userList
变量
小结