mybatis/mybatis-3 · error · ExecutorException

Two different properties are mapped to the same resultSet

Error message

Two different properties are mapped to the same resultSet

What it means

In multi-ResultSet statements (stored procedures with resultSet='...' mappings), each named ResultSet may drive at most one property mapping. addPendingChildRelation tracks the ResultMapping per resultSet name in nextResultMaps; when a second, different ResultMapping claims the same resultSet name, this ExecutorException is thrown.

Source

Thrown at src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java:719

      }
    }
  }

  private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping)
      throws SQLException {
    CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(),
        parentMapping.getColumn());
    PendingRelation deferLoad = new PendingRelation();
    deferLoad.metaObject = metaResultObject;
    deferLoad.propertyMapping = parentMapping;
    List<PendingRelation> relations = pendingRelations.computeIfAbsent(cacheKey, k -> new ArrayList<>());
    // issue #255
    relations.add(deferLoad);
    ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
    if (previous == null) {
      nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
    } else if (!previous.equals(parentMapping)) {
      throw new ExecutorException("Two different properties are mapped to the same resultSet");
    }
  }

  private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns)
      throws SQLException {
    CacheKey cacheKey = new CacheKey();
    cacheKey.update(resultMapping);
    if (columns != null && names != null) {
      String[] columnsArray = columns.split(",");
      String[] namesArray = names.split(",");
      for (int i = 0; i < columnsArray.length; i++) {
        Object value = rs.getString(columnsArray[i]);
        if (value != null) {
          cacheKey.update(namesArray[i]);
          cacheKey.update(value);
        }
      }
    }

View on GitHub (pinned to 008069adb1)

Solutions

  1. Give each child collection its own ResultSet name in the mapping so one name maps one property
  2. If two properties truly share one result set, map one collection and derive the second property from it in Java code
  3. Alter the stored procedure to emit separate result sets per collection

Example fix

// before
@Results({
  @Result(property="items", column="order_id", many=@Many(select="getItems"), resultSet="rs2"),
  @Result(property="notes", column="order_id", many=@Many(select="getNotes"), resultSet="rs2")
})
// after: separate result sets
@Results({
  @Result(property="items", column="order_id", many=@Many(select="getItems"), resultSet="rs2"),
  @Result(property="notes", column="order_id", many=@Many(select="getNotes"), resultSet="rs3")
})
Defensive patterns

Strategy: validation

Validate before calling

// Validate at startup: each resultSet name maps at most one property per statement
for (String id : cfg.getMappedStatementNames()) {
  Set<String> seen = new HashSet<>();
  for (ResultMap rm : cfg.getMappedStatement(id).getResultMaps()) {
    for (ResultMapping m : rm.getResultMappings()) {
      if (m.getResultSet() != null && !seen.add(m.getResultSet() + '|' + m.getProperty())) {
        // detect duplicates by resultSet name below instead
      }
    }
  }
}
Set<String> rsNames = new HashSet<>();
for (ResultMapping m : cfg.getResultMap("orderMap").getResultMappings()) {
  if (m.getResultSet() != null && !rsNames.add(m.getResultSet())) throw new IllegalStateException("Duplicate resultSet mapping: " + m.getResultSet());
}

Prevention

When it happens

Trigger: Two @Result/column mappings in one statement (or two statements feeding one resultMap) declare the same resultSet="foo" but map to different properties — e.g. @Result(property="a", resultSet="rs2") and @Result(property="b", resultSet="rs2") with differing columns.

Common situations: Copy-pasting @Result annotations for multiple children of a stored-procedure result and forgetting to give each child its own resultSet name; refactoring a stored proc to merge result sets without updating the mappings.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/dcaa08e97384fe73. Report an issue: GitHub.