前言
在Mapper接口中,有注解的方法,也有xml配置的方法,这一章我们主要介绍前者。
本文介绍的Mapper方法
@Select("select * from tb_image where md5 = #{md5}")ImageInfo byMd5(@Param(value = "md5") String md5);@Select("select * from tb_image where md5 = #{md5}") ImageInfo byMd5(@Param(value = "md5") String md5);@Select("select * from tb_image where md5 = #{md5}") ImageInfo byMd5(@Param(value = "md5") String md5);
序列图
注册Mapper
注册Mapper,将Mapper注册到knownMappers中,注意后面的是一个代理类,后续再开个单章介绍。同时将Mapper接口解析,代码中的config参数是Configuration的实体,主要是mybatis的配置信息。
public <T> void addMapper(Class<T> type) {// 注册knownMappers.put(type, new MapperProxyFactory<>(type));// 主要代码就是这两行MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);// 解析parser.parse();}public <T> void addMapper(Class<T> type) { // 注册 knownMappers.put(type, new MapperProxyFactory<>(type)); // 主要代码就是这两行 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); // 解析 parser.parse(); }public <T> void addMapper(Class<T> type) { // 注册 knownMappers.put(type, new MapperProxyFactory<>(type)); // 主要代码就是这两行 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); // 解析 parser.parse(); }
解析Mapper
Mapper里的每个方法都会创建一个statement,供后续执行使用。
解析Mapper中的方法
public void parse() {String resource = type.toString();// 加载xml配置,在XMLMapperBuilder中解析xml中的方法,这里忽略不讲loadXmlResource();// 每个Mapper加载一次configuration.addLoadedResource(resource);// 当前Mapper的命名空间assistant.setCurrentNamespace(type.getName());// 缓存注解解析,见后续单章parseCache();parseCacheRef();// 每个方法都需要生成一个statementfor (Method method : type.getMethods()) {// 忽略不能解析的方法,比如抽象、静态等if (!canHaveStatement(method)) {continue;}// 生成statement,保存到configurationparseStatement(method);}}public void parse() { String resource = type.toString(); // 加载xml配置,在XMLMapperBuilder中解析xml中的方法,这里忽略不讲 loadXmlResource(); // 每个Mapper加载一次 configuration.addLoadedResource(resource); // 当前Mapper的命名空间 assistant.setCurrentNamespace(type.getName()); // 缓存注解解析,见后续单章 parseCache(); parseCacheRef(); // 每个方法都需要生成一个statement for (Method method : type.getMethods()) { // 忽略不能解析的方法,比如抽象、静态等 if (!canHaveStatement(method)) { continue; } // 生成statement,保存到configuration parseStatement(method); } }public void parse() { String resource = type.toString(); // 加载xml配置,在XMLMapperBuilder中解析xml中的方法,这里忽略不讲 loadXmlResource(); // 每个Mapper加载一次 configuration.addLoadedResource(resource); // 当前Mapper的命名空间 assistant.setCurrentNamespace(type.getName()); // 缓存注解解析,见后续单章 parseCache(); parseCacheRef(); // 每个方法都需要生成一个statement for (Method method : type.getMethods()) { // 忽略不能解析的方法,比如抽象、静态等 if (!canHaveStatement(method)) { continue; } // 生成statement,保存到configuration parseStatement(method); } }
主要流程分为三个步骤:
- 解析Mapper对应的xml文件,并为xml文件里的每个方法都生成一个statement;
- 解析缓存注解,后续介绍;
- 解析注解方法;
生成statement
public MappedStatement addMappedStatement(...) {// 是否查询方法boolean isSelect = sqlCommandType == SqlCommandType.SELECT;// 生成statementMappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType).resource(resource).fetchSize(fetchSize).timeout(timeout).statementType(statementType).keyGenerator(keyGenerator).keyProperty(keyProperty).keyColumn(keyColumn).databaseId(databaseId).lang(lang).resultOrdered(resultOrdered).resultSets(resultSets).resultMaps(getStatementResultMaps(resultMap, resultType, id)).resultSetType(resultSetType).flushCacheRequired(valueOrDefault(flushCache, !isSelect)).useCache(valueOrDefault(useCache, isSelect)).cache(currentCache);// 语句的参数配置ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);if (statementParameterMap != null) {statementBuilder.parameterMap(statementParameterMap);}// Mapper里每个方法都会生成一个statementMappedStatement statement = statementBuilder.build();// 将statement放到mybatis上下文configuration.addMappedStatement(statement);return statement;}public MappedStatement addMappedStatement(...) { // 是否查询方法 boolean isSelect = sqlCommandType == SqlCommandType.SELECT; // 生成statement MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType) .resource(resource) .fetchSize(fetchSize) .timeout(timeout) .statementType(statementType) .keyGenerator(keyGenerator) .keyProperty(keyProperty) .keyColumn(keyColumn) .databaseId(databaseId) .lang(lang) .resultOrdered(resultOrdered) .resultSets(resultSets) .resultMaps(getStatementResultMaps(resultMap, resultType, id)) .resultSetType(resultSetType) .flushCacheRequired(valueOrDefault(flushCache, !isSelect)) .useCache(valueOrDefault(useCache, isSelect)) .cache(currentCache); // 语句的参数配置 ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id); if (statementParameterMap != null) { statementBuilder.parameterMap(statementParameterMap); } // Mapper里每个方法都会生成一个statement MappedStatement statement = statementBuilder.build(); // 将statement放到mybatis上下文 configuration.addMappedStatement(statement); return statement; }public MappedStatement addMappedStatement(...) { // 是否查询方法 boolean isSelect = sqlCommandType == SqlCommandType.SELECT; // 生成statement MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType) .resource(resource) .fetchSize(fetchSize) .timeout(timeout) .statementType(statementType) .keyGenerator(keyGenerator) .keyProperty(keyProperty) .keyColumn(keyColumn) .databaseId(databaseId) .lang(lang) .resultOrdered(resultOrdered) .resultSets(resultSets) .resultMaps(getStatementResultMaps(resultMap, resultType, id)) .resultSetType(resultSetType) .flushCacheRequired(valueOrDefault(flushCache, !isSelect)) .useCache(valueOrDefault(useCache, isSelect)) .cache(currentCache); // 语句的参数配置 ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id); if (statementParameterMap != null) { statementBuilder.parameterMap(statementParameterMap); } // Mapper里每个方法都会生成一个statement MappedStatement statement = statementBuilder.build(); // 将statement放到mybatis上下文 configuration.addMappedStatement(statement); return statement; }
将statement注册到Configuration里的mappedStatements结构中,后续执行的时候,直接从这里获取对应方法的statement
public void addMappedStatement(MappedStatement ms) {mappedStatements.put(ms.getId(), ms);}public void addMappedStatement(MappedStatement ms) { mappedStatements.put(ms.getId(), ms); }public void addMappedStatement(MappedStatement ms) { mappedStatements.put(ms.getId(), ms); }
替换sql中的占位符
在SqlSourceBuilder类中,对sql中的参数占位符进行替换
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;if (configuration.isShrinkWhitespacesInSql()) {sql = parser.parse(removeExtraWhitespaces(originalSql));} else {sql = parser.parse(originalSql);}// 从handler中获取请求参数mapreturn new StaticSqlSource(configuration, sql, handler.getParameterMappings());}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; if (configuration.isShrinkWhitespacesInSql()) { sql = parser.parse(removeExtraWhitespaces(originalSql)); } else { sql = parser.parse(originalSql); } // 从handler中获取请求参数map return new StaticSqlSource(configuration, sql, handler.getParameterMappings()); }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; if (configuration.isShrinkWhitespacesInSql()) { sql = parser.parse(removeExtraWhitespaces(originalSql)); } else { sql = parser.parse(originalSql); } // 从handler中获取请求参数map return new StaticSqlSource(configuration, sql, handler.getParameterMappings()); }
例子中的请求参数:ParameterMapping{property='md5', mode=IN, javaType=class java.lang.String, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}
替换效果如下:
最终Statement信息
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END