白市驿网站建设市网站建设

当前位置: 首页 > news >正文

白市驿网站建设,市网站建设,外贸网站怎么注册,电子商务网站怎么建设文章目录一、熟悉主要接口二、SqlSession的获取1、通过数据源获取SqlSession三、Mapper的获取与代理1、从SqlSession获取Mapper2、执行Mapper方法前准备逻辑3、SqlCommand的创建4、构造MethodSignature四、执行Mapper的核心方法1、执行Mapper的方法逻辑五、简单SELECT处理过程1… 文章目录一、熟悉主要接口二、SqlSession的获取1、通过数据源获取SqlSession三、Mapper的获取与代理1、从SqlSession获取Mapper2、执行Mapper方法前准备逻辑3、SqlCommand的创建4、构造MethodSignature四、执行Mapper的核心方法1、执行Mapper的方法逻辑五、简单SELECT处理过程1、对参数进行解析2、DefaultSqlSession的selectOne逻辑3、Executor的query4、查询数据库的逻辑1prepareStatement5、StatementHandler的query方法6、处理结果集1处理结果集2创建映射结果对象3根据columnName和type属性名映射赋值4applyPropertyMappings写在后面一、熟悉主要接口 DefaultSqlSessionSqlSession接口的默认实现类 Executor接口 BaseExecutor基础执行器封装了子类的公共方法包括一级缓存、延迟加载、回滚、关闭等功能 SimpleExecutor简单执行器每执行一条 sql都会打开一个 Statement执行完成后关闭 ReuseExecutor重用执行器相较于 SimpleExecutor 多了 Statement 的缓存功能其内部维护一个 MapString, Statement 每次编译完成的 Statement 都会进行缓存不会关闭 BatchExecutor批量执行器基于 JDBC 的 addBatch、executeBatch 功能并且在当前 sql 和上一条 sql 完全一样的时候重用Statement在调用doFlushStatements 的时候将数据刷新到数据库 CachingExecutor缓存执行器装饰器模式在开启缓存的时候。会在上面三种执行器的外面包上 CachingExecutor StatementHandler接口
MyBatis实际使用的StatementHandler就是RoutingStatementHandler拦截器拦截的也是RoutingStatementHandler。它会根据Exector类型创建对应的StatementHandler保存到属性delegate中所以插件分离还要分离出具体的StatementHandler。 BaseStatementHandler基础语句处理器抽象类它基本把语句处理器接口的核心部分都实现了包括配置绑定、执行器绑定、映射器绑定、参数处理器构建、结果集处理器构建、语句超时设置、语句关闭等并另外定义了新的方法 instantiateStatement 供不同子类实现以便获取不同类型的语句连接子类可以普通执行 SQL 语句也可以做预编译执行还可以执行存储过程等。 SimpleStatementHandler普通语句处理器继承 BaseStatementHandler 抽象类对应 java.sql.Statement 对象的处理处理普通的不带动态参数运行的 SQL即执行简单拼接的字符串语句同时由于 Statement 的特性SimpleStatementHandler 每次执行都需要编译 SQL 注意我们知道 SQL 的执行是需要编译和解析的。 PreparedStatementHandler预编译语句处理器继承 BaseStatementHandler 抽象类对应 java.sql.PrepareStatement 对象的处理相比上面的普通语句处理器它支持可变参数 SQL 执行由于 PrepareStatement 的特性它会进行预编译在缓存中一旦发现有预编译的命令会直接解析执行所以减少了再次编译环节能够有效提高系统性能并预防 SQL 注入攻击所以是系统默认也是我们推荐的语句处理器。 CallableStatementHandler存储过程处理器继承 BaseStatementHandler 抽象类对应 java.sql.CallableStatement 对象的处理很明了它是用来调用存储过程的增加了存储过程的函数调用以及输出/输入参数的处理支持。 RoutingStatementHandler路由语句处理器直接实现了 StatementHandler 接口作用如其名称确确实实只是起到了路由功能并把上面介绍到的三个语句处理器实例作为自身的委托对象而已所以执行器在构建语句处理器时都是直接 new 了 RoutingStatementHandler 实例。 RoutingStatementHandler路由。Mybatis实际使用的类拦截的StatementHandler实际就是它。它会根据Exector类型创建对应的StatementHandler保存到属性delegate中 ResultSetHandler接口处理Statement执行后产生的结果集生成结果列表处理存储过程执行后的输出参数 DefaultResultSetHandlerResultSetHandler的 默认实现类。 二、SqlSession的获取 SqlSessionFactory接口的默认实现是DefaultSqlSessionFactory其中实现了很多openSession的重载方法用来获取SqlSession有几个关键的参数 // DefaultSqlSessionFactory的重载方法 Override public SqlSession openSession() {return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } Override public SqlSession openSession(boolean autoCommit) {return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit); } Override public SqlSession openSession(ExecutorType execType) {return openSessionFromDataSource(execType, null, false); } Override public SqlSession openSession(TransactionIsolationLevel level) {return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false); } Override public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {return openSessionFromDataSource(execType, level, false); } Override public SqlSession openSession(ExecutorType execType, boolean autoCommit) {return openSessionFromDataSource(execType, null, autoCommit); }① ExecutorType public enum ExecutorType {SIMPLE, REUSE, BATCH // 默认是SIMPLE }② autoCommit // 是否自动提交 boolean autoCommit③ TransactionIsolationLevel事务等级 public enum TransactionIsolationLevel {NONE(Connection.TRANSACTION_NONE),READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE); }1、通过数据源获取SqlSession // org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx null;// 包装数据库连接。处理连接生命周期包括:连接的创建、准备、提交/回滚和关闭。try {final Environment environment configuration.getEnvironment();// 在配置文件中或者API方式定义默认的JdbcTransactionFactoryfinal TransactionFactory transactionFactory getTransactionFactoryFromEnvironment(environment);tx transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);final Executor executor configuration.newExecutor(tx, execType); // 创建执行器return new DefaultSqlSession(configuration, executor, autoCommit); // 创建默认的SqlSession} 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();} }我们来看一下创建执行器的逻辑 // org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType) public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType executorType null ? defaultExecutorType : executorType;executorType executorType null ? ExecutorType.SIMPLE : executorType; // 默认是SIMPLEExecutor 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);}// 责任链模式使用JDK动态代理增强所有的拦截器为后续的拦截器的使用做准备executor (Executor) interceptorChain.pluginAll(executor);return executor; }三、Mapper的获取与代理 1、从SqlSession获取Mapper 官方文档中提供了一种使用SqlSession做查询的实例 try (SqlSession session sqlSessionFactory.openSession()) {Blog blog (Blog) session.selectOne(org.mybatis.example.BlogMapper.selectBlog, 101); }但是推荐使用下面的方式进行处理 try (SqlSession session sqlSessionFactory.openSession()) {BlogMapper mapper session.getMapper(BlogMapper.class);Blog blog mapper.selectBlog(101); }我们对DefaultSqlSession的getMapper方法进行分析 // org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper Override public T T getMapper(ClassT type) {return configuration.getMapper(type, this); }// org.apache.ibatis.session.Configuration#getMapper public T T getMapper(ClassT type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession); }// org.apache.ibatis.binding.MapperRegistry#getMapper public T T getMapper(ClassT type, SqlSession sqlSession) {final MapperProxyFactoryT mapperProxyFactory (MapperProxyFactoryT) knownMappers.get(type);if (mapperProxyFactory null) {throw new BindingException(Type type is not known to the MapperRegistry.);}try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException(Error getting mapper instance. Cause: e, e);} }我们发现就是根据接口的Class类型从MapperRegistry中获取在SqlSessionFactory接口中我们分析到在创建SqlSessionFactory时会在MapperRegistry存放一个MapperProxyFactory此时我们会直接拿出来这个MapperProxyFactory。 最终调用mapperProxyFactory.newInstance方法 // org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.binding.MapperProxyT) protected T newInstance(MapperProxyT mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }// org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession) public T newInstance(SqlSession sqlSession) {final MapperProxyT mapperProxy new MapperProxy(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy); }最终使用就JDK动态代理生成了一个代理类用于处理mapper的方法。 2、执行Mapper方法前准备逻辑 上面说到从SqlSession中获取的Mapper是被JDK动态代理过的JDK动态代理请自行学习当执行Mapper接口的方法时会调用其关键方法为MapperProxy的invoke方法 // org.apache.ibatis.binding.MapperProxy#invoke Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (Object.class.equals(method.getDeclaringClass())) {// Object的方法直接放行不需要代理return method.invoke(this, args);} else { // 调用invoke方法return cachedInvoker(method).invoke(proxy, method, args, sqlSession);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);} }// org.apache.ibatis.binding.MapperProxy#cachedInvoker private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {try {// 如果缓存没有的话将方法放入缓存return MapUtil.computeIfAbsent(methodCache, method, m - {if (m.isDefault()) {// 如果是default方法用这种方式执行try {if (privateLookupInMethod null) {return new DefaultMethodInvoker(getMethodHandleJava8(method));} else {return new DefaultMethodInvoker(getMethodHandleJava9(method));}} catch (IllegalAccessException | InstantiationException | InvocationTargetException| NoSuchMethodException e) {throw new RuntimeException(e);}} else { // 正常的方法会创建PlainMethodInvoker装饰MapperMethodreturn new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));}});} catch (RuntimeException re) {Throwable cause re.getCause();throw cause null ? re : cause;} } 最终会new一个MapperMethodMapperMethod构造方法中包含着两个关键对象的创建 public MapperMethod(Class? mapperInterface, Method method, Configuration config) {this.command new SqlCommand(config, mapperInterface, method);this.method new MethodSignature(config, mapperInterface, method); }3、SqlCommand的创建 我们看一下SqlCommand的构造方法 // org.apache.ibatis.binding.MapperMethod.SqlCommand#SqlCommand public SqlCommand(Configuration configuration, Class? mapperInterface, Method method) {final String methodName method.getName();final Class? declaringClass method.getDeclaringClass();// 获取MappedStatementMappedStatement ms resolveMappedStatement(mapperInterface, methodName, declaringClass,configuration);if (ms null) {// Flush注解标注的接口if (method.getAnnotation(Flush.class) ! null) {name null;type SqlCommandType.FLUSH;} else { // 没找到XML对应的statementthrow new BindingException(Invalid bound statement (not found): mapperInterface.getName() . methodName);}} else { // 查找到MappedStatementname ms.getId();type ms.getSqlCommandType();if (type SqlCommandType.UNKNOWN) {throw new BindingException(Unknown execution method for: name);}} }在resolveMappedStatement方法中有以下逻辑 // org.apache.ibatis.binding.MapperMethod.SqlCommand#resolveMappedStatement private MappedStatement resolveMappedStatement(Class? mapperInterface, String methodName,Class? declaringClass, Configuration configuration) {// 接口全限定名 方法名就是statementIdString statementId mapperInterface.getName() . methodName;if (configuration.hasStatement(statementId)) { // 在addMapper时就会解析xmlreturn configuration.getMappedStatement(statementId);} else if (mapperInterface.equals(declaringClass)) {return null;}// 查询父接口for (Class? superInterface : mapperInterface.getInterfaces()) {if (declaringClass.isAssignableFrom(superInterface)) {MappedStatement ms resolveMappedStatement(superInterface, methodName,declaringClass, configuration);if (ms ! null) {return ms;}}}return null; }此时我们获取了MappedStatement并且包装好了SqlCommand。 到这我们应该了解了MyBatis的Statement其实和JDBC的Statement的含义有些区别MyBatis的Statement其实就是代表着XML中的每一个SELECT、UPDATE、DELETE等标签中的SQL信息。 SqlCommand中包含着Mapper.xml的id与SQL类型。 4、构造MethodSignature // MethodSignature的构造方法 public MethodSignature(Configuration configuration, Class? mapperInterface, Method method) {Type resolvedReturnType TypeParameterResolver.resolveReturnType(method, mapperInterface);// 设置返回值类型if (resolvedReturnType instanceof Class?) {this.returnType (Class?) resolvedReturnType;} else if (resolvedReturnType instanceof ParameterizedType) {this.returnType (Class?) ((ParameterizedType) resolvedReturnType).getRawType();} else {this.returnType method.getReturnType();}// 是否返回voidthis.returnsVoid void.class.equals(this.returnType);// 是否返回多条this.returnsMany configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();// 是否返回游标this.returnsCursor Cursor.class.equals(this.returnType);// 是否返回Optionalthis.returnsOptional Optional.class.equals(this.returnType);this.mapKey getMapKey(method);this.returnsMap this.mapKey ! null;this.rowBoundsIndex getUniqueParamIndex(method, RowBounds.class);this.resultHandlerIndex getUniqueParamIndex(method, ResultHandler.class);this.paramNameResolver new ParamNameResolver(configuration, method); }处理一些方法签名相关信息。 四、执行Mapper的核心方法 上面我们分析到使用PlainMethodInvoker包装了MapperMethodPlainMethodInvoker的invoke方法JDK动态代理的最终会调用MapperMethod的execute方法 private static class PlainMethodInvoker implements MapperMethodInvoker {private final MapperMethod mapperMethod;public PlainMethodInvoker(MapperMethod mapperMethod) {super();this.mapperMethod mapperMethod;}Overridepublic Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {return mapperMethod.execute(sqlSession, args);} }1、执行Mapper的方法逻辑 正常的方法会调用MapperMethod的execute方法该方法中包含着对sql的操作增删改查 // org.apache.ibatis.binding.MapperMethod#execute public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {case INSERT: {Object param method.convertArgsToSqlCommandParam(args);result rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param method.convertArgsToSqlCommandParam(args);result rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param method.convertArgsToSqlCommandParam(args);result rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:// 返回值为voidif (method.returnsVoid() method.hasResultHandler()) {executeWithResultHandler(sqlSession, args);result null;} else if (method.returnsMany()) { // 返回多个result 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);result sqlSession.selectOne(command.getName(), param);if (method.returnsOptional() (result null || !method.getReturnType().equals(result.getClass()))) {result Optional.ofNullable(result);}}break;case FLUSH: // FLUSHresult 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; }我们此处按照官方文档只分析简单的SELECT查询其他同理。 五、简单SELECT处理过程 1、对参数进行解析 先执行convertArgsToSqlCommandParam方法对参数进行解析 // org.apache.ibatis.binding.MapperMethod.MethodSignature#convertArgsToSqlCommandParam public Object convertArgsToSqlCommandParam(Object[] args) {return paramNameResolver.getNamedParams(args); }// org.apache.ibatis.reflection.ParamNameResolver#getNamedParams public Object getNamedParams(Object[] args) {final int paramCount names.size();if (args null || paramCount 0) { // mapper中的sql不需要参数return null;} else if (!hasParamAnnotation paramCount 1) { // mapper中的sql需要1个参数Object value args[names.firstKey()];return wrapToMapIfCollection(value, useActualParamName ? names.get(0) : null);} else { // mapper中的sql需要多个参数final MapString, Object param new ParamMap();int i 0;for (Map.EntryInteger, String entry : names.entrySet()) {param.put(entry.getValue(), args[entry.getKey()]);// add generic param names (param1, param2, …)final String genericParamName GENERIC_NAME_PREFIX (i 1);// ensure not to overwrite parameter named with Paramif (!names.containsValue(genericParamName)) {param.put(genericParamName, args[entry.getKey()]);}i;}return param;} }// org.apache.ibatis.reflection.ParamNameResolver#wrapToMapIfCollection // 只需要一个参数时需要判断是否是集合、数组或者普通类型 public static Object wrapToMapIfCollection(Object object, String actualParamName) {if (object instanceof Collection) { ParamMapObject map new ParamMap();map.put(collection, object);if (object instanceof List) {map.put(list, object);}Optional.ofNullable(actualParamName).ifPresent(name - map.put(name, object));return map;} else if (object ! null object.getClass().isArray()) {ParamMapObject map new ParamMap();map.put(array, object);Optional.ofNullable(actualParamName).ifPresent(name - map.put(name, object));return map;}return object; }2、DefaultSqlSession的selectOne逻辑 解析完参数之后然后执行DefaultSqlSession的selectOne逻辑 // org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object) Override public T T selectOne(String statement, Object parameter) {// Popular vote was to return null on 0 results and throw exception on too many.ListT 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;} }// org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object) Override public E ListE selectList(String statement, Object parameter) {// RowBounds返回结果集最大值return this.selectList(statement, parameter, RowBounds.DEFAULT); }// org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds) Override public E ListE selectList(String statement, Object parameter, RowBounds rowBounds) {return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER); }// org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler) private E ListE selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {try {// 获取到已经处理过的MappedStatement 就是对应Mapper中的sql等信息MappedStatement ms configuration.getMappedStatement(statement);// 最终调用执行器的query// RowBounds是用来逻辑分页按照条件将数据从数据库查询到内存中在内存中进行分页// wrapCollection(parameter)是用来装饰集合或者数组参数return executor.query(ms, wrapCollection(parameter), rowBounds, handler);} catch (Exception e) {throw ExceptionFactory.wrapException(Error querying database. Cause: e, e);} finally {ErrorContext.instance().reset();} }3、Executor的query Executor接口中包含了增删改查以及提交回滚与对缓存的处理是真正的sql执行器。 E ListE query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;Configuration中cacheEnabled属性值默认为true会执行CachingExecutor的query方法 org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler) Override public E ListE query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {// 获取SQL基本信息sql参数会变成 ? 比如“SELECT * FROM user WHERE id ? ”BoundSql boundSql ms.getBoundSql(parameter);// 获取缓存key通过算法确保key的唯一性CacheKey key createCacheKey(ms, parameter, rowBounds, boundSql);return query(ms, parameter, rowBounds, resultHandler, key, boundSql); }// org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql) Override public E ListE query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)throws SQLException {// 获取二级缓存Cache cache ms.getCache();if (cache ! null) {// 当为select语句时flushCache默认为false表示任何时候语句被调用都不会去清空本地缓存和二级缓存// 当为insert、update、delete语句时,useCache默认为true表示会将本条语句的结果进行二级缓存// 刷新二级缓存 存在缓存且flushCache为true时flushCacheIfRequired(ms);if (ms.isUseCache() resultHandler null) {ensureNoOutParams(ms, boundSql);// // 从二级缓存中查询数据SuppressWarnings(unchecked)ListE list (ListE) 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); }// BaseExecutor执行query // org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql) SuppressWarnings(unchecked) Override public E ListE 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();}ListE list;try {queryStack;list resultHandler null ? (ListE) 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 #601deferredLoads.clear();if (configuration.getLocalCacheScope() LocalCacheScope.STATEMENT) {// issue #482clearLocalCache();}}return list; } 4、查询数据库的逻辑 如果一级缓存没有数据则从数据库查询数据。 // org.apache.ibatis.executor.BaseExecutor#queryFromDatabase private E ListE queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {ListE 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; }在doQuery方法中最终执行的是SimpleExecutor的doQuery方法正式进行JDBC那一套了 // org.apache.ibatis.executor.SimpleExecutor#doQuery Override public E ListE doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt null; // java.sql.Statement try {// 获取Configuration对象Configuration configuration ms.getConfiguration();// 创建RoutingStatementHandler用来处理Statement// RoutingStatementHandler类中初始化delegate类SimpleStatementHandler、PreparedStatementHandlerStatementHandler handler configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);// 子流程1设置参数stmt prepareStatement(handler, ms.getStatementLog());return handler.query(stmt, resultHandler);} finally {// Statement关闭closeStatement(stmt);} }1prepareStatement 我们看一下准备Statement的逻辑 // org.apache.ibatis.executor.SimpleExecutor#prepareStatement private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {Statement stmt;Connection connection getConnection(statementLog);// 获取数据库连接// 创建StatementPreparedStatement、Statement、CallableStatementstmt handler.prepare(connection, transaction.getTimeout());// 相关参数处理handler.parameterize(stmt);return stmt; }获取连接的逻辑 // org.apache.ibatis.executor.BaseExecutor#getConnection protected Connection getConnection(Log statementLog) throws SQLException {Connection connection transaction.getConnection(); // 从事务管理器中拿到连接if (statementLog.isDebugEnabled()) {return ConnectionLogger.newInstance(connection, statementLog, queryStack);} else {return connection;} }// org.apache.ibatis.transaction.jdbc.JdbcTransaction#getConnection Override public Connection getConnection() throws SQLException {if (connection null) {openConnection();}return connection; }protected void openConnection() throws SQLException {if (log.isDebugEnabled()) {log.debug(Opening JDBC Connection);}connection dataSource.getConnection();if (level ! null) {connection.setTransactionIsolation(level.getLevel());}setDesiredAutoCommit(autoCommit); }我们发现获取链接就是默认从DataSource中获取链接。 MyBatis中对Connection 的管理是交给Transaction接口管理的Transaction接口包含了对Connection 的获取、提交回滚、关闭等操作。 在其实现类中实际上最终的获取和关闭Connection 是由DataSource来处理的相当于使用Transaction接口做了一层包装。 拿到Connection 之后就开始获取Statement了 // org.apache.ibatis.executor.statement.BaseStatementHandler#prepare Override public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {ErrorContext.instance().sql(boundSql.getSql());Statement statement null;try {// connection.createStatement() 创建Statementstatement 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);} }获取完Statement开始设置参数 // org.apache.ibatis.executor.statement.PreparedStatementHandler#parameterize Override public void parameterize(Statement statement) throws SQLException { // 通过ParameterHandler处理参数parameterHandler.setParameters((PreparedStatement) statement); }// org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters Override public void setParameters(PreparedStatement ps) {ErrorContext.instance().activity(setting parameters).object(mappedStatement.getParameterMap().getId());ListParameterMapping 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 paramsvalue 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) {jdbcType configuration.getJdbcTypeForNull();}try {// 调用typeHandler的setParameter方法typeHandler.setParameter(ps, i 1, value, jdbcType);} catch (TypeException | SQLException e) {throw new TypeException(Could not set parameters for mapping: parameterMapping . Cause: e, e);}}}} }到此时Statement已经准备就绪了也通过typeHandler将参数注入到Statement中了。 5、StatementHandler的query方法 // org.apache.ibatis.executor.statement.RoutingStatementHandler#query Override public E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {return delegate.query(statement, resultHandler); }// org.apache.ibatis.executor.statement.PreparedStatementHandler#query Override public E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {PreparedStatement ps (PreparedStatement) statement;ps.execute(); // 执行如果是true就可以拿到ResultSetreturn resultSetHandler.handleResultSets(ps); // 提取结果集 } 6、处理结果集 execute执行完毕之后就是拿到结果集了 // org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets Override public ListObject handleResultSets(Statement stmt) throws SQLException {ErrorContext.instance().activity(handling results).object(mappedStatement.getId());// select标签的resultMap属性可以指定多个值多个值之间用逗号,分割final ListObject multipleResults new ArrayList();int resultSetCount 0;// 这里是获取第一个结果集将传统JDBC的ResultSet包装成一个包含结果列元信息的ResultSetWrapper对象ResultSetWrapper rsw getFirstResultSet(stmt);// 这里是获取所有要映射的ResultMap按照逗号分割出来的ListResultMap 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); }1处理结果集 // org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSet private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, ListObject multipleResults, ResultMapping parentMapping) throws SQLException {try {if (parentMapping ! null) {// 处理行数据handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);} else {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 {// 关闭ResultSet// issue #228 (close resultsets)closeResultSet(rsw.getResultSet());} }// org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValues 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);} }// org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForSimpleResultMap private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler? resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {DefaultResultContextObject 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);// 处理对象嵌套的映射关系// 使用ResultHandler进行结果集映射storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);} }// 将查询结果封装到POJO中 // org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, java.lang.String) private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {// 延迟加载的映射信息final ResultLoaderMap lazyLoader new ResultLoaderMap();// 通过反射创建对象Object rowValue createResultObject(rsw, resultMap, lazyLoader, columnPrefix);if (rowValue ! null !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {final MetaObject metaObject configuration.newMetaObject(rowValue); // 创建MetaObjectboolean foundValues this.useConstructorMappings;// 是否应用自动映射也就是通过resultType进行映射if (shouldApplyAutomaticMappings(resultMap, false)) {// 根据columnName和type属性名映射赋值Mapper中的resultType映射foundValues applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;}// 根据我们配置ResultMap的column和property映射赋值也就是Mapper中的resultMap映射// 如果映射存在nestedQueryId会调用getNestedQueryMappingValue方法获取返回值foundValues applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;foundValues lazyLoader.size() 0 || foundValues;rowValue foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;}return rowValue; }2创建映射结果对象 // org.apache.ibatis.executor.resultset.DefaultResultSetHandler#createResultObject(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, org.apache.ibatis.executor.loader.ResultLoaderMap, java.lang.String) private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {this.useConstructorMappings false; // reset previous mapping resultfinal ListClass? constructorArgTypes new ArrayList();final ListObject constructorArgs new ArrayList();// 创建结果映射的PO类对象Object resultObject createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);if (resultObject ! null !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {// 获取要映射的PO类的属性信息final ListResultMapping propertyMappings resultMap.getPropertyResultMappings();for (ResultMapping propertyMapping : propertyMappings) {// issue gcode #109 issue #149// 延迟加载处理if (propertyMapping.getNestedQueryId() ! null propertyMapping.isLazy()) {// 通过动态代理工厂创建延迟加载的代理对象resultObject configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);break;}}}this.useConstructorMappings resultObject ! null !constructorArgTypes.isEmpty(); // set current mapping resultreturn resultObject; }// org.apache.ibatis.executor.resultset.DefaultResultSetHandler#createResultObject(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, java.util.Listjava.lang.Class?, java.util.Listjava.lang.Object, java.lang.String) private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ListClass? constructorArgTypes, ListObject constructorArgs, String columnPrefix)throws SQLException {final Class? resultType resultMap.getType();final MetaClass metaType MetaClass.forClass(resultType, reflectorFactory);final ListResultMapping constructorMappings resultMap.getConstructorResultMappings();if (hasTypeHandlerForResultObject(rsw, resultType)) {return createPrimitiveResultObject(rsw, resultMap, columnPrefix);} else if (!constructorMappings.isEmpty()) {return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {// 对象工厂创建对象return objectFactory.create(resultType);} else if (shouldApplyAutomaticMappings(resultMap, false)) {return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);}throw new ExecutorException(Do not know how to create an instance of resultType); }3根据columnName和type属性名映射赋值 // org.apache.ibatis.executor.resultset.DefaultResultSetHandler#applyAutomaticMappings private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {ListUnMappedColumnAutoMapping autoMapping createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);boolean foundValues false;if (!autoMapping.isEmpty()) {for (UnMappedColumnAutoMapping mapping : autoMapping) {final Object value mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);if (value ! null) {foundValues true;}if (value ! null || (configuration.isCallSettersOnNulls() !mapping.primitive)) {// gcode issue #377, call setter on nulls (value is not found)metaObject.setValue(mapping.property, value);}}}return foundValues; }4applyPropertyMappings 根据我们配置ResultMap的column和property映射赋值,如果映射存在nestedQueryId会调用getNestedQueryMappingValue方法获取返回值 // org.apache.ibatis.executor.resultset.DefaultResultSetHandler#applyPropertyMappings private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {final ListString mappedColumnNames rsw.getMappedColumnNames(resultMap, columnPrefix);boolean foundValues false;final ListResultMapping propertyMappings resultMap.getPropertyResultMappings();for (ResultMapping propertyMapping : propertyMappings) {String column prependPrefix(propertyMapping.getColumn(), columnPrefix);if (propertyMapping.getNestedResultMapId() ! null) {// the user added a column attribute to a nested result map, ignore itcolumn null;}if (propertyMapping.isCompositeResult()|| (column ! null mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))|| propertyMapping.getResultSet() ! null) {Object value getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);// issue #541 make property optionalfinal String property propertyMapping.getProperty();if (property null) {continue;} else if (value DEFERRED) {foundValues true;continue;}if (value ! null) {foundValues true;}if (value ! null || (configuration.isCallSettersOnNulls() !metaObject.getSetterType(property).isPrimitive())) {// gcode issue #377, call setter on nulls (value is not found)metaObject.setValue(property, value);}}}return foundValues; }写在后面 如果本文对你有帮助请点赞收藏关注一下吧 ~