{"record":{"id":"dd4479768fe46510","repo":"apache/shardingsphere","slug":"there-is-already-a-transaction-in-progress","errorCode":null,"errorMessage":"There is already a transaction in progress","messagePattern":"There is already a transaction in progress","errorType":"exception","errorClass":"InTransactionException","httpStatus":null,"severity":"error","filePath":"proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/BeginTransactionProxyBackendHandler.java","lineNumber":58,"sourceCode":"    \n    private final ProxyBackendTransactionManager transactionManager;\n    \n    private final DialectDatabaseMetaData dialectDatabaseMetaData;\n    \n    public BeginTransactionProxyBackendHandler(final TCLStatement sqlStatement, final ConnectionSession connectionSession) {\n        this.sqlStatement = sqlStatement;\n        this.connectionSession = connectionSession;\n        transactionManager = new ProxyBackendTransactionManager(connectionSession.getDatabaseConnectionManager());\n        dialectDatabaseMetaData = new DatabaseTypeRegistry(connectionSession.getProtocolType()).getDialectDatabaseMetaData();\n    }\n    \n    @Override\n    public ResponseHeader execute() throws SQLException {\n        if (connectionSession.getTransactionStatus().isInTransaction()) {\n            if (dialectDatabaseMetaData.getTransactionOption().isSupportAutoCommitInNestedTransaction()) {\n                transactionManager.commit();\n            } else if (dialectDatabaseMetaData.getSchemaOption().getDefaultSchema().isPresent()) {\n                throw new InTransactionException();\n            }\n        }\n        transactionManager.begin();\n        return new UpdateResponseHeader(sqlStatement);\n    }\n}\n","sourceCodeStart":40,"sourceCodeEnd":65,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/BeginTransactionProxyBackendHandler.java#L40-L65","documentation":"InTransactionException ('There is already a transaction in progress') thrown by BeginTransactionProxyBackendHandler.execute when a BEGIN arrives while connectionSession.getTransactionStatus().isInTransaction() is true, the dialect does not support auto-commit in nested transactions, and the dialect has a default schema (schema option exposes getDefaultSchema()). In that combination the proxy refuses to silently nest transactions and surfaces the same error the backing database (e.g. PostgreSQL) would give.","triggerScenarios":"Client sends BEGIN twice without COMMIT/ROLLBACK, or sends BEGIN while an implicitly started transaction is open, on a dialect like PostgreSQL where TransactionOption.isSupportAutoCommitInNestedTransaction() is false and a default schema exists. MySQL-style dialects instead commit the outer transaction and begin a new one.","commonSituations":"ORM/connection pools that auto-BEGIN (autocommit=false plus an eager BEGIN) layered on manual transaction control; retry logic re-issuing BEGIN after a lost response; drivers enabling implicit transactions before SET commands that themselves start transactions; migrating an app from MySQL (nested BEGIN tolerated) to PostgreSQL.","solutions":["Issue COMMIT or ROLLBACK before sending another BEGIN, or let the driver/ORM own transaction boundaries exclusively","Disable eager/auto BEGIN in the client pool or ORM (e.g. do not wrap every statement in an explicit transaction)","Guard client code: check the session transaction state (e.g. JDBC Connection.getAutoCommit() / transaction status) before BEGIN"],"exampleFix":"-- before\nBEGIN;\nSELECT 1;\nBEGIN;  -- ERROR: There is already a transaction in progress\n\n-- after\nBEGIN;\nSELECT 1;\nCOMMIT;\nBEGIN;","handlingStrategy":"validation","validationCode":"// client-side: check before sending BEGIN over the proxy connection\nif (!connection.getAutoCommit()) {\n    connection.commit(); // or rollback(): close the open transaction first\n}\nconnection.setAutoCommit(false); // effectively BEGIN","typeGuard":null,"tryCatchPattern":"try {\n    statement.execute(\"BEGIN\");\n} catch (final SQLException ex) {\n    if (ex.getMessage() != null && ex.getMessage().contains(\"There is already a transaction in progress\")) {\n        statement.execute(\"COMMIT\");\n        statement.execute(\"BEGIN\"); // retry once from a clean state\n    } else {\n        throw ex;\n    }\n}","preventionTips":["Let exactly one layer (driver autocommit, ORM, or manual BEGIN) own transaction start","On PostgreSQL dialect, always pair BEGIN/COMMIT and never re-BEGIN inside an open transaction","In retry logic, track transaction state instead of blindly replaying BEGIN"],"tags":["transaction","tcl","postgresql","proxy","session-state"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}