{"record":{"id":"5de0575a2bf4de4c","repo":"hibernate/hibernate-orm","slug":"transaction-timeout-expired","errorCode":null,"errorMessage":"Transaction timeout expired","messagePattern":"Transaction timeout expired","errorType":"exception","errorClass":"TransactionException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java","lineNumber":323,"sourceCode":"\n\t@Override\n\tpublic void setTransactionTimeOut(int seconds) {\n\t\ttransactionTimeOutInstant = System.currentTimeMillis() + ( seconds * 1000L );\n\t}\n\n\t@Override\n\tpublic void flushBeforeTransactionCompletion() {\n\t\tgetJdbcSessionOwner().flushBeforeTransactionCompletion();\n\t}\n\n\t@Override\n\tpublic int determineRemainingTransactionTimeOutPeriod() {\n\t\tif ( transactionTimeOutInstant < 0 ) {\n\t\t\treturn -1;\n\t\t}\n\t\tfinal long millisecondsRemaining = transactionTimeOutInstant - System.currentTimeMillis();\n\t\tif ( millisecondsRemaining <= 0L ) {\n\t\t\tthrow new TransactionException( \"Transaction timeout expired\" );\n\t\t}\n\t\treturn Math.max( (int) (millisecondsRemaining / 1000), 1 );\n\t}\n\n\t@Override\n\tpublic void afterStatementExecution() {\n\t\tfinal var connectionReleaseMode = getLogicalConnection().resolvedConnectionReleaseMode();\n\t\tif ( TRACE_ENABLED ) {\n\t\t\tJDBC_LOGGER.statementExecutionComplete( connectionReleaseMode, hashCode() );\n\t\t}\n\t\tif ( connectionReleaseMode == AFTER_STATEMENT ) {\n\t\t\tif ( !releasesEnabled ) {\n\t\t\t\tJDBC_LOGGER.skippingAggressiveRelease( \"manually disabled\" );\n\t\t\t}\n\t\t\telse if ( hasRegisteredResources() ) {\n\t\t\t\tJDBC_LOGGER.skippingAggressiveRelease( \"registered resources\" );\n\t\t\t}\n\t\t\telse {","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java#L305-L341","documentation":"JdbcCoordinatorImpl.determineRemainingTransactionTimeOutPeriod() computes the milliseconds left before the configured transaction timeout instant; if the deadline has already passed it throws TransactionException('Transaction timeout expired'). The remaining-time value is used to apply statement query timeouts when preparing mutation and query statements (MutationStatementPreparerImpl and StatementPreparerImpl), so the exception typically surfaces during flush or statement preparation inside an over-deadline transaction.","triggerScenarios":"A transaction timeout was set (Spring @Transactional(timeout=...), JTA transaction timeout, or transaction manager timeout propagated to setTransactionTimeOutInstant) and elapsed before Hibernate finished preparing/executing statements — long flushes, slow SQL, lock waits, or oversized batch jobs.","commonSituations":"Batch imports inside one @Transactional; pessimistic-lock waits; a statement-level query timeout being derived from the remaining transaction time; heavy first-level-cache flushes at commit.","solutions":["Raise the transaction timeout for the long-running unit of work (e.g. @Transactional(timeout = 300))","Optimize or split the work: chunk batches into multiple transactions, fix slow statements and lock contention","Keep entity counts per transaction small so flush does not blow the deadline"],"exampleFix":"// before\n@Transactional(timeout = 5)\npublic void importAll(List<Row> rows) { rows.forEach(repo::save); }\n\n// after\n@Transactional(timeout = 300)\npublic void importAll(List<Row> rows) { /* also consider chunking */ }","handlingStrategy":"retry","validationCode":"// check remaining time in long loops and commit chunks early\nlong deadline = System.currentTimeMillis() + timeoutMillis;\nfor (Row r : rows) {\n    if (System.currentTimeMillis() > deadline - margin) { commitChunkAndStartNewTx(); }\n    save(r);\n}","typeGuard":null,"tryCatchPattern":"catch (TransactionException e) {\n    if (e.getMessage().contains(\"Transaction timeout expired\")) {\n        // rollback and retry the unit of work with a fresh transaction\n    }\n}","preventionTips":["Size transaction timeouts to the real work (rows * per-row cost)","Chunk batch jobs into multiple transactions instead of one giant one","Monitor slow statements and lock waits that eat the budget"],"tags":["transaction","timeout","flush","spring","hibernate"],"backgroundTag":"transaction-timeout-expired","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}