成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

【深入淺出MyBatis筆記】MyBatis的解析和運(yùn)行原理

bitkylin / 1183人閱讀

摘要:的解析和運(yùn)行原理構(gòu)建過(guò)程提供創(chuàng)建的核心接口。在構(gòu)造器初始化時(shí)會(huì)根據(jù)和的方法解析為命令。數(shù)據(jù)庫(kù)會(huì)話(huà)器定義了一個(gè)對(duì)象的適配器,它是一個(gè)接口對(duì)象,構(gòu)造器根據(jù)配置來(lái)適配對(duì)應(yīng)的對(duì)象。它的作用是給實(shí)現(xiàn)類(lèi)對(duì)象的使用提供一個(gè)統(tǒng)一簡(jiǎn)易的使用適配器。

MyBatis的解析和運(yùn)行原理 構(gòu)建SqlSessionFactory過(guò)程

SqlSessionFactory提供創(chuàng)建MyBatis的核心接口SqlSession。MyBatis采用構(gòu)造模式去創(chuàng)建SqlSessionFactory,我們可以通過(guò)SqlSessionFactoryBuilder去構(gòu)建。

第一步,通過(guò)XMLConfigBuilder解析配置的XML文件,讀出配置參數(shù),并將讀取的數(shù)據(jù)存入這個(gè)Configuration類(lèi)中。

第二步,使用Configuration對(duì)象去創(chuàng)建SqlSessionFactory。

SqlSessionFactoryBuilder的源碼:

public class SqlSessionFactoryBuilder {
  .....
  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
      try {
        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
        // XMLConfigBuilder解析配置的XML文件,構(gòu)建Configuration
        return build(parser.parse());
      } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error building SqlSession.", e);
      } finally {
        ErrorContext.instance().reset();
        try {
          inputStream.close();
        } catch (IOException e) {
          // Intentionally ignore. Prefer previous error.
        }
      }
  }

  // 使用Configuration對(duì)象去創(chuàng)建SqlSessionFactory
  public SqlSessionFactory build(Configuration config) {
      // SqlSessionFactory是一個(gè)接口,為此MyBatis提供了一個(gè)默認(rèn)實(shí)現(xiàn)類(lèi)
      return new DefaultSqlSessionFactory(config);
  }
}
構(gòu)建Configuration

在XMLConfigBuilder中,MyBatis會(huì)讀出所有XML配置的信息,然后將這些信息保存到Configuration類(lèi)的單例中。
它會(huì)做如下初始化:

properties全局參數(shù)

setting設(shè)置

typeAliases別名

typeHandler類(lèi)型處理器

ObjectFactory對(duì)象

plugin插件

environment環(huán)境

DatabaseIdProvider數(shù)據(jù)庫(kù)標(biāo)識(shí)

Mapper映射器

XMLConfigBuilder的源碼:

public class XMLConfigBuilder extends BaseBuilder {
  ...
  public Configuration parse() {
      if (parsed) {
        throw new BuilderException("Each XMLConfigBuilder can only be used once.");
      }
      parsed = true;
      // 解析配置文件,設(shè)置Configuration
      parseConfiguration(parser.evalNode("/configuration"));
      return configuration;
    }

  private void parseConfiguration(XNode root) {
    // 讀出MyBatis配置文件中的configuration下的各個(gè)子標(biāo)簽元素
    // 把全部信息保存到Configuration類(lèi)的單例中
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      // 設(shè)置mapper映射器
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
}
映射器的內(nèi)部組成

XMLMapperBuilder負(fù)責(zé)對(duì)配置文件中的Mapper映射器進(jìn)行解析,其中在configurationElement方法中可以看出來(lái),會(huì)分別對(duì)配置文件中的parameterMap、resultMap、sql、select|insert|update|delete元素進(jìn)行解析。

public class XMLMapperBuilder extends BaseBuilder {
  public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
      // 解析配置文件中的mapper映射器
      configurationElement(parser.evalNode("/mapper"));
      configuration.addLoadedResource(resource);
      bindMapperForNamespace();
    }

    parsePendingResultMaps();
    parsePendingCacheRefs();
    parsePendingStatements();
  }

  private void configurationElement(XNode context) {
    try {
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.equals("")) {
        throw new BuilderException("Mapper"s namespace cannot be empty");
      }
      builderAssistant.setCurrentNamespace(namespace);
      cacheRefElement(context.evalNode("cache-ref"));
      cacheElement(context.evalNode("cache"));
      // 解析我們配置的parameterMap元素
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      // 解析我們配置的resultMap元素
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      // 解析我們配置的sql元素
      sqlElement(context.evalNodes("/mapper/sql"));
       // 解析我們配置的select、insert、update、delete元素
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
    }
  }
}

在方法buildStatementFromContext()中,會(huì)根據(jù)配置信息創(chuàng)建一個(gè)MappedStatement對(duì)象。

MappedStatement,它保存映射器的一個(gè)節(jié)點(diǎn)(select|insert|update|delete)。包括許多我們配置的SQL、SQL的id、緩存信息、resultMap、parameterType、resultType、languageDriver等重要配置內(nèi)容。

public final class MappedStatement {
  private Configuration configuration;
  private String id;
  private StatementType statementType;
  private ResultSetType resultSetType;
  private SqlSource sqlSource;
  private Cache cache;
  private ParameterMap parameterMap;
  private List resultMaps;
  private boolean flushCacheRequired;
  private boolean useCache;
  private SqlCommandType sqlCommandType;
  private KeyGenerator keyGenerator;
  private String databaseId;
  private LanguageDriver lang;
  ......
}

SqlSource,它是提供BoundSql對(duì)象的地方,它是MappedStatement的一個(gè)屬性。

public interface SqlSource {

  BoundSql getBoundSql(Object parameterObject);

}

BoundSql,它是建立SQL和參數(shù)的地方。

public class BoundSql {

  private final String sql;
  private final List parameterMappings;
  private final Object parameterObject;
  private final Map additionalParameters;
  private final MetaObject metaParameters;
}
SqlSession運(yùn)行過(guò)程

SqlSession是一個(gè)接口,在MyBatis中有一個(gè)默認(rèn)實(shí)現(xiàn)DefaultSqlSession。我們構(gòu)建SqlSessionFactory就可以輕易地拿到SqlSession了。通過(guò)SqlSession,我們拿到Mapper,之后可以做查詢(xún)、插入、更新、刪除的方法。

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

其實(shí)getMapper()方法拿到的mapper是通過(guò)Java動(dòng)態(tài)代理實(shí)現(xiàn)的。從getMapper()方法逐級(jí)往下看,可以發(fā)現(xiàn)在MapperRegistry類(lèi)的getMapper()方法中會(huì)拿到一個(gè)MapperProxyFactory的對(duì)象,最后是通過(guò)MapperProxyFactory對(duì)象去生成一個(gè)Mapper的。

public class DefaultSqlSession implements SqlSession {
  .....
  @Override
  public  T getMapper(Class type) {
    return configuration.getMapper(type, this);
  }
}

public class Configuration {
  .....
  public  T getMapper(Class type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }
}

public class MapperRegistry {
  ......
  public  T getMapper(Class type, SqlSession sqlSession) {
    final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) 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);
    }
  }
}
映射器的動(dòng)態(tài)代理

Mapper映射是通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)的,MapperProxyFactory用來(lái)生成動(dòng)態(tài)代理對(duì)象。

public class MapperProxyFactory {
  ......
  protected T newInstance(MapperProxy mapperProxy) {
      // 動(dòng)態(tài)代理
      return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
      final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);
      return newInstance(mapperProxy);
  }
}

在MapperProxyFactory的newInstance方法中可以看到有一個(gè)MapperProxy對(duì)象,MapperProxy實(shí)現(xiàn)InvocationHandler接口(動(dòng)態(tài)代理需要實(shí)現(xiàn)這一接口)的代理方法invoke(), 這invoke()方法實(shí)現(xiàn)對(duì)被代理類(lèi)的方法進(jìn)行攔截。
而在invoke()方法中,MapperMethod對(duì)象會(huì)執(zhí)行Mapper接口的查詢(xún)或其他方法。

public class MapperProxy implements InvocationHandler, Serializable {
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        // 先判斷是否一個(gè)類(lèi),在這里Mapper顯然是一個(gè)接口
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
        // 判斷是不是接口默認(rèn)實(shí)現(xiàn)方法
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    // 緩存中取出MapperMethod,不存在的話(huà),則根據(jù)Configuration初始化一個(gè)
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    // 執(zhí)行Mapper接口的查詢(xún)或其他方法
    return mapperMethod.execute(sqlSession, args);
}

private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }
}

MapperMethod采用命令模式運(yùn)行,并根據(jù)上下文跳轉(zhuǎn)。MapperMethod在構(gòu)造器初始化時(shí)會(huì)根據(jù)Configuration和Mapper的Method方法解析為SqlCommand命令。之后在execute方法,根據(jù)SqlCommand的Type進(jìn)行跳轉(zhuǎn)。然后采用命令模式,SqlSession通過(guò)SqlCommand執(zhí)行插入、更新、查詢(xún)、選擇等方法。

public MapperMethod(Class mapperInterface, Method method, Configuration config) {
    // 根據(jù)Configuration和Mapper的Method方法解析為SqlCommand
    this.command = new SqlCommand(config, mapperInterface, method);
    this.method = new MethodSignature(config, mapperInterface, method);
}

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    // 根據(jù)Type進(jìn)行跳轉(zhuǎn),通過(guò)sqlSession執(zhí)行相關(guān)的操作
    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:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method "" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
}

看到這里,應(yīng)該大概知道了MyBatis為什么只用Mapper接口便能夠運(yùn)行SQL,因?yàn)橛成淦鞯腦ML文件的命名空間namespace對(duì)應(yīng)的便是這個(gè)接口的全路徑,那么它根據(jù)全路徑和方法名便能夠綁定起來(lái),通過(guò)動(dòng)態(tài)代理技術(shù),讓這個(gè)接口跑起來(lái)。而后采用命令模式,最后還是使用SqlSession接口的方法使得它能夠執(zhí)行查詢(xún),有了這層封裝我們便可以使用這個(gè)接口編程。
不過(guò)還是可以看到,最后插入、更新、刪除、查詢(xún)操作還是會(huì)回到SqlSession中進(jìn)行處理。

Sqlsession下的四大對(duì)象

我們已經(jīng)知道了映射器其實(shí)就是一個(gè)動(dòng)態(tài)代理對(duì)象,進(jìn)入到了MapperMethod的execute方法。它經(jīng)過(guò)簡(jiǎn)單判斷就是進(jìn)入了SqlSession的刪除、更新、插入、選擇等方法。sqlSession執(zhí)行一個(gè)查詢(xún)操作??梢钥吹绞峭ㄟ^(guò)一個(gè)executor來(lái)執(zhí)行的。

其實(shí)SqlSession中的Executor執(zhí)行器負(fù)責(zé)調(diào)度StatementHandler、ParameterHandler、ResultHandler等來(lái)執(zhí)行相關(guān)的SQL。

StatementHandler:使用數(shù)據(jù)庫(kù)的Statement(PrepareStatement)執(zhí)行操作

ParameterHandler:用于SQL對(duì)參數(shù)的處理

ResultHandler:進(jìn)行最后數(shù)據(jù)集(ResultSet)的封裝返回處理

Sqlsession其實(shí)是一個(gè)接口,它有一個(gè)DefaultSqlSession的默認(rèn)實(shí)現(xiàn)類(lèi)。

public class DefaultSqlSession implements SqlSession {
  private final Configuration configuration;
  // Executor執(zhí)行器,負(fù)責(zé)調(diào)度SQL的執(zhí)行
  private final Executor executor;

  ......
  @Override
  public  List selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      // 通過(guò)executor執(zhí)行查詢(xún)操作
      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執(zhí)行器

執(zhí)行器起到了至關(guān)重要的作用,它是一個(gè)真正執(zhí)行Java和數(shù)據(jù)庫(kù)交互的東西。在MyBatis中存在三種執(zhí)行器,我們可以在MyBatis的配置文件中進(jìn)行選擇。

SIMPLE,簡(jiǎn)易執(zhí)行器

REUSE,是一種執(zhí)行器重用預(yù)處理語(yǔ)句

BATCH,執(zhí)行器重用語(yǔ)句和批量更新,她是針對(duì)批量專(zhuān)用的執(zhí)行器

它們都提供了查詢(xún)和更新方法,以及相關(guān)的事務(wù)方法。

Executor是通過(guò)Configuration類(lèi)創(chuàng)建的,MyBatis將根據(jù)配置類(lèi)型去確定你需要?jiǎng)?chuàng)建三種執(zhí)行器中的哪一種。

public class Configuration {
  ......
    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);
    }
    // MyBatis插件,構(gòu)建一層層的動(dòng)態(tài)代理對(duì)象
    // 在調(diào)度真實(shí)的方法之前執(zhí)行配置插件的代碼
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }
}
顯然MyBatis根據(jù)Configuration來(lái)構(gòu)建StatementHandler,然后使用prepareStatement方法,對(duì)SQL編譯并對(duì)參數(shù)進(jìn)行初始化,resultHandler再組裝查詢(xún)結(jié)果返回給調(diào)用者來(lái)完成一次查詢(xún)。
public class SimpleExecutor extends BaseExecutor {
    .....
    @Override
    public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;
        try {
            Configuration configuration = ms.getConfiguration();
            // 根據(jù)Configuration來(lái)構(gòu)建StatementHandler
            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            // 對(duì)SQL編譯并對(duì)參數(shù)進(jìn)行初始化
            stmt = prepareStatement(handler, ms.getStatementLog());
            // 組裝查詢(xún)結(jié)果返回給調(diào)用者
            return handler.query(stmt, resultHandler);
        } finally {
            closeStatement(stmt);
        }
    }

  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    // 進(jìn)行預(yù)編譯和基礎(chǔ)設(shè)置
    stmt = handler.prepare(connection, transaction.getTimeout());
    // 設(shè)置參數(shù)
    handler.parameterize(stmt);
    return stmt;
  }
}
StatementHandler數(shù)據(jù)庫(kù)會(huì)話(huà)器

StatementHandler就是專(zhuān)門(mén)處理數(shù)據(jù)庫(kù)會(huì)話(huà)的。

創(chuàng)建StatementHandler:

public class Configuration {
    ......
    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
        // MyBatis插件,生成一層層的動(dòng)態(tài)代理對(duì)象
        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
        return statementHandler;
  }
}

RoutingStatementHandler其實(shí)不是我們真實(shí)的服務(wù)對(duì)象,它是通過(guò)適配模式找到對(duì)應(yīng)的StatementHandler來(lái)執(zhí)行。
StatementHandler分為三種:

SimleStatementHandler

PrepareStatementHandler

CallableStatementHandler

在初始化RoutingStatementHandler對(duì)象的時(shí)候它會(huì)根據(jù)上下文環(huán)境來(lái)決定創(chuàng)建哪個(gè)StatementHandler對(duì)象。

public class RoutingStatementHandler implements StatementHandler {
    ......
    private final StatementHandler delegate;

    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());
    }
  }
}

數(shù)據(jù)庫(kù)會(huì)話(huà)器定義了一個(gè)對(duì)象的適配器delegate,它是一個(gè)StatementHandler接口對(duì)象,構(gòu)造器根據(jù)配置來(lái)適配對(duì)應(yīng)的StatementHandler對(duì)象。它的作用是給實(shí)現(xiàn)類(lèi)對(duì)象的使用提供一個(gè)統(tǒng)一、簡(jiǎn)易的使用適配器。此為對(duì)象的適配模式,可以讓我們使用現(xiàn)有的類(lèi)和方法對(duì)外提供服務(wù),也可以根據(jù)實(shí)際的需求對(duì)外屏蔽一些方法,甚至加入新的服務(wù)。

在執(zhí)行器Executor執(zhí)行查詢(xún)操作的時(shí)候,我們看到PreparedStatementHandler的三個(gè)方法:prepare、parameterize和query。

public abstract class BaseStatementHandler implements StatementHandler {
  .....
    @Override
    public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        ErrorContext.instance().sql(boundSql.getSql());
        Statement statement = null;
        try {
            // 對(duì)SQL進(jìn)行了預(yù)編譯
            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);
    }
  }
}

public class PreparedStatementHandler extends BaseStatementHandler {
    @Override
    public void parameterize(Statement statement) throws SQLException {
        // 設(shè)置參數(shù)
        parameterHandler.setParameters((PreparedStatement) statement);
    }

    @Override
    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);
        }
    }

    @Override
    public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        // 執(zhí)行SQL
        ps.execute();
        // resultSetHandler封裝結(jié)果返回
        return resultSetHandler. handleResultSets(ps);
    } 
}
一條查詢(xún)SQL的執(zhí)行過(guò)程,Executor會(huì)先調(diào)用StatementHandler的prepare()方法預(yù)編譯SQL語(yǔ)句,同時(shí)設(shè)置一些基本運(yùn)行的參數(shù)。然后用parameterize()方法啟動(dòng)ParameterHandler設(shè)置參數(shù),完成預(yù)編譯,跟著就是執(zhí)行查詢(xún)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69531.html

相關(guān)文章

  • Java深入-框架技巧

    摘要:從使用到原理學(xué)習(xí)線(xiàn)程池關(guān)于線(xiàn)程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實(shí)現(xiàn)在軟件開(kāi)發(fā)中,分散于應(yīng)用中多出的功能被稱(chēng)為橫切關(guān)注點(diǎn)如事務(wù)安全緩存等。 Java 程序媛手把手教你設(shè)計(jì)模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經(jīng)風(fēng)雨慢慢變老,回首走過(guò)的點(diǎn)點(diǎn)滴滴,依然清楚的記得當(dāng)初愛(ài)情萌芽的模樣…… Java 進(jìn)階面試問(wèn)題列表 -...

    chengtao1633 評(píng)論0 收藏0
  • Java學(xué)習(xí)路線(xiàn)總結(jié),搬磚工逆襲Java架構(gòu)師(全網(wǎng)最強(qiáng))

    摘要:哪吒社區(qū)技能樹(shù)打卡打卡貼函數(shù)式接口簡(jiǎn)介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號(hào)作者架構(gòu)師奮斗者掃描主頁(yè)左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無(wú)意間聽(tīng)到領(lǐng)導(dǎo)們的談話(huà),現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡(jiǎn)而言之,不缺干 ? 哪吒社區(qū)Java技能樹(shù)打卡?【打卡貼 day2...

    Scorpion 評(píng)論0 收藏0
  • 深入淺出MyBatis筆記】插件

    摘要:插件插件接口在中使用插件,我們必須實(shí)現(xiàn)接口。它將直接覆蓋你所攔截對(duì)象原有的方法,因此它是插件的核心方法。插件在對(duì)象中的保存插件的代理和反射設(shè)計(jì)插件用的是責(zé)任鏈模式,的責(zé)任鏈?zhǔn)怯扇ザx的。 插件 1、插件接口 在MyBatis中使用插件,我們必須實(shí)現(xiàn)接口Interceptor。 public interface Interceptor { // 它將直接覆蓋你所攔截對(duì)象原有的方法,因...

    leon 評(píng)論0 收藏0
  • 帶你深入淺出MyBatis技術(shù)原理與實(shí)戰(zhàn)(PDF實(shí)戰(zhàn)實(shí)踐)

    摘要:目錄其中每個(gè)章節(jié)知識(shí)點(diǎn)都是相關(guān)連由淺入深的一步步全面分析了技術(shù)原理以及實(shí)戰(zhàn)由于文案較長(zhǎng)想深入學(xué)習(xí)以及對(duì)于該文檔感興趣的朋友們可以加群免費(fèi)獲取。這些場(chǎng)景在大量的編碼中使用,具備較強(qiáng)的實(shí)用價(jià)值,這些內(nèi)容都是通過(guò)實(shí)戰(zhàn)得來(lái)的,供讀者們參考。 前言系統(tǒng)掌握MyBatis編程技巧已經(jīng)成了用Java構(gòu)建移動(dòng)互聯(lián)網(wǎng)網(wǎng)站的必要條件 本文主要講解了Mybatis的應(yīng)用,解析了其原理,從而形成一個(gè)完整的知識(shí)...

    MoAir 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<