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

  1. Wrap the work: startManagedSession(); try { ...; commit(); } catch { rollback(); } finally { close(); }.
  2. If you never use managed mode, commit on a factory-opened SqlSession instead of the manager.
  3. 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

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


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