mybatis/mybatis-3 · error · SqlSessionException
Error: Cannot commit. No managed session is started.
Error message
Error: Cannot commit. No managed session is started.
What it means
SqlSessionManager.commit() forwards to the thread-local managed session and throws SqlSessionException 'Cannot commit. No managed session is started.' when localSqlSession is empty. Commit is only meaningful inside the managed-session lifecycle (startManagedSession ... commit ... close); without a started session there is no transaction to commit.
Source
Thrown at src/main/java/org/apache/ibatis/session/SqlSessionManager.java:284
throw new SqlSessionException("Error: Cannot get connection. No managed session is started.");
}
return sqlSession.getConnection();
}
@Override
public void clearCache() {
final SqlSession sqlSession = localSqlSession.get();
if (sqlSession == null) {
throw new SqlSessionException("Error: Cannot clear the cache. No managed session is started.");
}
sqlSession.clearCache();
}
@Override
public void commit() {
final SqlSession sqlSession = localSqlSession.get();
if (sqlSession == null) {
throw new SqlSessionException("Error: Cannot commit. No managed session is started.");
}
sqlSession.commit();
}
@Override
public void commit(boolean force) {
final SqlSession sqlSession = localSqlSession.get();
if (sqlSession == null) {
throw new SqlSessionException("Error: Cannot commit. No managed session is started.");
}
sqlSession.commit(force);
}
@Override
public void rollback() {
final SqlSession sqlSession = localSqlSession.get();
if (sqlSession == null) {
throw new SqlSessionException("Error: Cannot rollback. No managed session is started.");View on GitHub (pinned to 008069adb1)
Solutions
- Wrap the work: startManagedSession(); try { ...; commit(); } catch { rollback(); } finally { close(); }.
- If you never use managed mode, commit on a factory-opened SqlSession instead of the manager.
- For Spring apps, prefer SqlSessionTemplate/DataSourceTransactionManager which handle commit lifecycle.
Example fix
// before
sqlSessionManager.update("insertUser", u);
sqlSessionManager.commit(); // throws
// after
sqlSessionManager.startManagedSession();
try {
sqlSessionManager.update("insertUser", u);
sqlSessionManager.commit();
} finally { sqlSessionManager.close(); } Defensive patterns
Strategy: validation
Validate before calling
sqlSessionManager.startManagedSession();
try { /* work */ sqlSessionManager.commit(); }
finally { if (sqlSessionManager.isManagedSessionStarted()) sqlSessionManager.close(); } Try / catch
try { commit(); } catch (SqlSessionException e) { /* 'No managed session' -> add startManagedSession before work */ throw e; } Prevention
- Standardize the lifecycle template: start -> try work+commit -> catch rollback -> finally close.
- Start the session before the try block so commit/rollback are always reachable.
- In Spring, prefer SqlSessionTemplate so the platform manages commits.
When it happens
Trigger: commit() invoked before startManagedSession(); after close() already detached the session; from another thread than the session owner.
Common situations: Hand-rolled transaction blocks that skip the start call on an error path; code moved into @Async methods losing the ThreadLocal session; refactoring from SqlSession (factory-opened) to SqlSessionManager without adding startManagedSession.
Related errors
- Error: Cannot get connection. No managed session is starte
- Error: Cannot clear the cache. No managed session is start
- Error: Cannot rollback. No managed session is started.
- Error: Cannot close. No managed session is started.
- Cannot commit, transaction is already closed
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/511897b2f4a564b8.
Report an issue: GitHub.