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);
}
@OverrideView on GitHub (pinned to 008069adb1)
Solutions
- Set useCache="false" on the CALLABLE statement, exactly as the message instructs
- Alternatively return procedure results as a result set (SELECT inside the proc) instead of OUT params if you want caching semantics
- Scope <cache> declarations so procedure-heavy mappers are not cached
- 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
- Mark every CALLABLE statement with OUT/INOUT params useCache="false"
- Audit mappers when enabling cacheEnabled or adding <cache/>
- Prefer result-set-returning procedures when caching is desired
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
- Invalid bound statement (not found): {mapperInterface}.{meth
- Type {type} is not known to the MapperRegistry.
- Error resolving JdbcType. Cause: {cause}
- Error resolving ResultSetType. Cause: {cause}
- Error resolving ParameterMode. Cause: {cause}
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/baaaee2383550036.
Report an issue: GitHub.