当前位置: 代码迷 >> 综合 >> Mapper 接口如何与写 SQL 的 XML 文件进行绑定的?
  详细解决方案

Mapper 接口如何与写 SQL 的 XML 文件进行绑定的?

热度:60   发布时间:2024-02-26 16:31:50.0
  • Mapper 接口与 XML 文件的绑定是通过 XML 里 mapper 标签的 namespace 值与 Mapper 接口的 包路径.接口名 进行绑定

  • Mapper 接口的方法名与 XML 文件中的 sql、select、insert、update、delete 标签的 id 参数值进行绑定

  • 其中涉及到了 MappedStatement 的 id、SqlCommand 的 name 的值为 Mapper 接口的 包路径.接口名.方法名

 

源码分析

要点 1、Mapper 接口与 XML 文件的绑定是通过 XML 里 mapper 标签的 namespace 值与 Mapper 接口的 包路径.接口名 进行绑定

源码体现在 XMLMapperBuilder 的 bindMapperForNamespace 方法

private void bindMapperForNamespace() {String namespace = builderAssistant.getCurrentNamespace();if (namespace != null) {Class<?> boundType = null;try {boundType = Resources.classForName(namespace);} catch (ClassNotFoundException e) {// ignore, bound type is not required}if (boundType != null && !configuration.hasMapper(boundType)) {// Spring may not know the real resource name so we set a flag// to prevent loading again this resource from the mapper interface// look at MapperAnnotationBuilder#loadXmlResourceconfiguration.addLoadedResource("namespace:" + namespace);configuration.addMapper(boundType);}}
}

 

 

要点 2、Mapper 接口的方法名与 XML 文件中的 sql、select、insert、update、delete 标签的 id 参数值进行绑定

源码体现在两个部分

1)生成 id 与 MappedStatement 对象注册到 configuration

XMLMapperBuilder configurationElement 方法中

//sql标签
sqlElement(context.evalNodes("/mapper/sql"));
//select、insert、update、delete标签
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));

 

XMLMapperBuilder sqlElement 方法中

String id = context.getStringAttribute("id");
id = builderAssistant.applyCurrentNamespace(id, false);
if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {sqlFragments.put(id, context);
}

 

XMLStatementBuilder parseStatementNode 方法中

//获取 Mapper xml 中标签 id
String id = context.getStringAttribute("id");
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,resultSetTypeEnum, flushCache, useCache, resultOrdered,keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);

 

MapperBuilderAssistant addMappedStatement 方法中

id = applyCurrentNamespace(id, false);

 

MapperBuilderAssistant applyCurrentNamespace 方法中

return currentNamespace + "." + base;

 

MapperBuilderAssistant addMappedStatement 方法中,最后把 MappedStatement 注册到 configuration 对象中

configuration.addMappedStatement(statement);

 

 

2)根据 Mapper 接口方法查到并调用对应的 MappedStatement,完成绑定

MapperProxy cachedInvoker 方法创建 PlainMethodInvoker 对象,创建了 MapperMethod 对象

return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));

 

MapperMethod 对象的 SqlCommand 中的 name 属性根据解析设置为对应的 MappedStatement 的 id

MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,configuration);
name = ms.getId();

 

MapperMethod execute 方法 SqlCommand 类型,通过 sqlSession 根据 SqlCommand 的 name(上一步被设置为 对应的 MappedStatement 的 id) 找到 MappedStatement 执行 select、insert、update、delete

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: {...return result;}
}

 

 


【Java面试题与答案】整理推荐

  • 基础与语法
  • 集合
  • 网络编程
  • 并发编程
  • Web
  • 安全
  • 设计模式
  • 框架
  • 算法与数据结构
  • 异常
  • 文件解析与生成
  • Linux
  • MySQL
  • Oracle
  • Redis
  • Dubbo