mybatis 在运行时注入 Mapper xml

mybatis inject Mapper xml while runtime

在 Mybatis 中,是否可以将基于 java 的配置与基于 xml 的映射器混合使用?

在配置mybatis时,我想使用POJO,因为我可以在运行时配置。

当注册 mapperConfiguration 时,我必须生成 mapper.xml 在运行时。

我知道有

 <mappers>
      <mapper resource = "mybatis/Student.xml"/>
 </mappers>

可以嵌入到mybatis配置文件中

但是我想在运行时注入不同的Mapper,甚至,我想在运行时生成一个不同的Mapperxml文件并注入到MybatisConfiguration.

这可能吗?如果是这样,我该怎么做?谢谢。

是的,您可以在运行时使用 SqlSessionFactory 工厂创建新的 Mapper 对象:

xml:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="configLocation" value="classpath:mybatis/mybatis.xml"/>
    <property name="dataSource" ref="dataSource"/>
</bean>

-- 更新于 2017-05-09,加载 mapper.xml --- 这是我从 mybatis-3.4.0-sources.jar!org/apache/ibatis/builder/xmlXMLConfigBuilder

中找到的代码

我想新的 mapper.xml 文件可以被

解析并注册到配置中
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();

-- org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XNode 父节点)--

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 
      // ....
    }
    // else 
    // ....
}

这里是org.apache.ibatis.builder.xml.XMLMapperBuilder#parse()

的过程
public void parse() {
  if (!configuration.isResourceLoaded(resource)) {
    configurationElement(parser.evalNode("/mapper"));
    configuration.addLoadedResource(resource);
    bindMapperForNamespace();
  }

  parsePendingResultMaps();
  parsePendingChacheRefs();
  parsePendingStatements();
}

是的,您可以通过编程方式添加映射器。假设您有一个名为 StudentMapper 的映射器。它可能有注释,或者 class 路径上可能有一个映射文件,具有匹配的完全限定 class 名称。然后你可以像这样添加映射器:

SqlSessionFactory factory = ...
factory.getConfiguration().addMapper(StudentMapper.class);

... 并像这样使用它:

Student student;
try (SqlSession session = factory.openSession()) {
  StudentMapper mapper = session.getMapper(StudentMapper.class);
  student = mapper.get(id);
}