mybatis/mybatis-3 · error · ExecutorException

Caching stored procedures with OUT params is not supported.

Error message

Caching stored procedures with OUT params is not supported.  Please configure useCache=false in ${statementId} statement.

What it means

CachingExecutor (second-level cache decorator) validates via ensureNoOutParams(): if a CALLABLE statement (stored procedure) has any parameter mapping with mode != IN (OUT or INOUT), and the statement is executed on a cache-enabled path, it throws ExecutorException 'Caching stored procedures with OUT params is not supported. Please configure useCache=false in <statementId> statement.' Rationale: OUT parameters are populated per call on the caller's parameter object; a cached result cannot fill them, so caching would silently return wrong OUT values.

Source

Thrown at src/main/java/org/apache/ibatis/executor/CachingExecutor.java:139

    tcm.commit();
  }

  @Override
  public void rollback(boolean required) throws SQLException {
    try {
      delegate.rollback(required);
    } finally {
      if (required) {
        tcm.rollback();
      }
    }
  }

  private void ensureNoOutParams(MappedStatement ms, BoundSql boundSql) {
    if (ms.getStatementType() == StatementType.CALLABLE) {
      for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
        if (parameterMapping.getMode() != ParameterMode.IN) {
          throw new ExecutorException(
              "Caching stored procedures with OUT params is not supported.  Please configure useCache=false in "
                  + ms.getId() + " statement.");
        }
      }
    }
  }

  @Override
  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    return delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql);
  }

  @Override
  public boolean isCached(MappedStatement ms, CacheKey key) {
    return delegate.isCached(ms, key);
  }

  @Override

View on GitHub (pinned to 008069adb1)

Solutions

  1. Set useCache="false" on the CALLABLE statement, exactly as the message instructs
  2. Alternatively return procedure results as a result set (SELECT inside the proc) instead of OUT params if you want caching semantics
  3. Scope <cache> declarations so procedure-heavy mappers are not cached
  4. Verify with the parameterMappings that modes are declared correctly — an accidental mode=OUT on an input-only param also triggers this

Example fix

<!-- before -->
<select id="getCount" statementType="CALLABLE" resultType="int">
  { call get_user_count(#{userId, mode=IN}, #{count, mode=OUT, jdbcType=INTEGER}) }
</select>

<!-- after -->
<select id="getCount" statementType="CALLABLE" resultType="int" useCache="false">
  { call get_user_count(#{userId, mode=IN}, #{count, mode=OUT, jdbcType=INTEGER}) }
</select>
Defensive patterns

Strategy: validation

Validate before calling

// Before enabling second-level cache on a mapper, scan its CALLABLE statements:
Configuration cfg = configuration;
for (MappedStatement ms : cfg.getMappedStatements().values()) {
  if (ms.getStatementType() == StatementType.CALLABLE && ms.isUseCache()) {
    for (ParameterMapping pm : ms.getBoundSql(null).getParameterMappings()) {
      if (pm.getMode() != ParameterMode.IN) {
        throw new IllegalStateException(ms.getId() + " needs useCache=false (OUT params)");
      }
    }
  }
}

Try / catch

try {
  sqlSession.selectOne("callGetCount", params);
} catch (ExecutorException e) {
  if (e.getMessage().contains("OUT params is not supported")) {
    // set useCache=false on the named statement, or disable caching for that mapper
  } else throw e;
}

Prevention

When it happens

Trigger: A <select statementType="CALLABLE"> with #{param, mode=OUT, jdbcType=...} mappings executed while second-level cache is enabled for that statement (useCache defaults true); enabling cacheEnabled=true globally and calling existing stored-procedure selects with OUT params; upgrading configs where cache was toggled on.

Common situations: Calling stored procedures that return values via output parameters (SQL Server/Oracle style) after enabling <setting name="cacheEnabled" value="true"/> or adding <cache/> to a mapper; reusing mapper XML from a non-cached setup in a cached one.

Related errors


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