在mybatis中StatementType的值决定了由什么对象来执行咱们的SQL语句。本文来分析下在mybatis中具体是怎么处理的。java
StatementType是一个枚举类型。以下:node
/** * @author Clinton Begin */ public enum StatementType { STATEMENT, PREPARED, CALLABLE }
选项 | 说明 |
---|---|
STATEMENT | 对应于Statement对象,有SQL注入的风险 |
PREPARED | PreparedStatement,预编译处理 |
CALLABLE | CallableStatement通常调用存储过程的时候使用 |
咱们能够在映射文件中经过‘statementType’属性设置,以下:sql
注意默认是'PREPARED ',经过源码分析咱们能够查看到。mybatis
咱们要从源码中发现StatementType的处理,应该是从加载配置文件的地方开始查看,因此咱们从'new SqlSessionFactoryBuilder().build(in);'这行代码入手app
//InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); InputStream in = TestMybatis.class.getResourceAsStream("/mybatis-config.xml"); // 获取SqlSessionFactory对象 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
进入build方法中查看ide
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); // 配置文件解析的重点是 'parser.parse()'这行代码 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. } } }
进入==parse==方法中源码分析
public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; // 进入 parseConfiguration(parser.evalNode("/configuration")); return configuration; } private void parseConfiguration(XNode root) { 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")); // 上面都是解析主配置文件中子节点,直接进入本方法 mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
==mapperElement==方法,该方法会根据咱们在mappers中不一样的配置作出不一样的处理。咱们直接看resource的方式fetch
private void mapperElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { if ("package".equals(child.getName())) { String mapperPackage = child.getStringAttribute("name"); configuration.addMappers(mapperPackage); } else { String resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); String mapperClass = child.getStringAttribute("class"); if (resource != null && url == null && mapperClass == null) { ErrorContext.instance().resource(resource); // 加载配置文件 InputStream inputStream = Resources.getResourceAsStream(resource); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); // 解析配置文件的方法 进入 mapperParser.parse(); } else if (resource == null && url != null && mapperClass == null) { ErrorContext.instance().resource(url); InputStream inputStream = Resources.getUrlAsStream(url); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); mapperParser.parse(); } else if (resource == null && url == null && mapperClass != null) { Class<?> mapperInterface = Resources.classForName(mapperClass); configuration.addMapper(mapperInterface); } else { throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); } } } } }
进入 ==mapperParser.parse()== 方法查看ui
public void parse() { if (!configuration.isResourceLoaded(resource)) { // 解析根节点 configurationElement(parser.evalNode("/mapper")); configuration.addLoadedResource(resource); // 绑定名称空间 bindMapperForNamespace(); } parsePendingResultMaps(); parsePendingCacheRefs(); // 重点本方法,解析未处理的Statements parsePendingStatements(); }
进入==parsePendingStatements==方法:this
private void parsePendingStatements() { Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements(); synchronized (incompleteStatements) { Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator(); while (iter.hasNext()) { try { // 解析咱们的select|update|insert|delete节点 iter.next().parseStatementNode(); iter.remove(); } catch (IncompleteElementException e) { // Statement is still missing a resource... } } } }
进入==parseStatementNode== 方法
public void parseStatementNode() { String id = context.getStringAttribute("id"); String databaseId = context.getStringAttribute("databaseId"); if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) { return; } Integer fetchSize = context.getIntAttribute("fetchSize"); Integer timeout = context.getIntAttribute("timeout"); String parameterMap = context.getStringAttribute("parameterMap"); String parameterType = context.getStringAttribute("parameterType"); Class<?> parameterTypeClass = resolveClass(parameterType); String resultMap = context.getStringAttribute("resultMap"); String resultType = context.getStringAttribute("resultType"); String lang = context.getStringAttribute("lang"); LanguageDriver langDriver = getLanguageDriver(lang); Class<?> resultTypeClass = resolveClass(resultType); String resultSetType = context.getStringAttribute("resultSetType"); // 重点代码,看截图 StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString())); ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType); String nodeName = context.getNode().getNodeName(); SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH)); boolean isSelect = sqlCommandType == SqlCommandType.SELECT; boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect); boolean useCache = context.getBooleanAttribute("useCache", isSelect); boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false); // Include Fragments before parsing XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant); includeParser.applyIncludes(context.getNode()); // Parse selectKey after includes and remove them. processSelectKeyNodes(id, parameterTypeClass, langDriver); // Parse the SQL (pre: <selectKey> and <include> were parsed and removed) SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass); String resultSets = context.getStringAttribute("resultSets"); String keyProperty = context.getStringAttribute("keyProperty"); String keyColumn = context.getStringAttribute("keyColumn"); KeyGenerator keyGenerator; String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX; keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true); if (configuration.hasKeyGenerator(keyStatementId)) { keyGenerator = configuration.getKeyGenerator(keyStatementId); } else { keyGenerator = context.getBooleanAttribute("useGeneratedKeys", configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType)) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE; } builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets); }
最后解析完这个select|insert|update|delete节点的信息被封装到了一个MapperedStatement对象中。
至此StatementType解析阶段的内容分析完了~