{
  "id": "java/transaction-rolled-back-deadlock",
  "signature": "org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction was rolled back because it has been marked as rollback-only",
  "signature_zh": "org.springframework.transaction.TransactionSystemException：无法提交JPA事务；嵌套异常为javax.persistence.RollbackException：事务已回滚，因为它被标记为仅回滚",
  "regex": "org\\.springframework\\.transaction\\.TransactionSystemException: Could not commit JPA transaction; nested exception is javax\\.persistence\\.RollbackException: Transaction was rolled back because it has been marked as rollback-only",
  "domain": "java",
  "category": "runtime_error",
  "subcategory": null,
  "root_cause": "This error occurs when a transaction is marked for rollback-only (e.g., due to a data integrity violation or optimistic locking failure) but the outer transaction context attempts to commit it, typically in a nested transaction or service layer where an exception was caught and swallowed.",
  "root_cause_type": "generic",
  "root_cause_zh": "当事务被标记为仅回滚（例如由于数据完整性违规或乐观锁定失败），但外部事务上下文尝试提交它时发生，通常在嵌套事务或服务层中捕获并吞没了异常。",
  "versions": [
    {
      "version": "Spring Boot 2.7.x",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    },
    {
      "version": "Spring Boot 3.2.x",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    },
    {
      "version": "Hibernate 5.6.x",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    },
    {
      "version": "Hibernate 6.3.x",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    }
  ],
  "os_specific": {},
  "dead_ends": [
    {
      "action": "Adding @Transactional(rollbackFor = Exception.class) to all methods",
      "why_fails": "This does not prevent the rollback-only marking; it only ensures exceptions trigger rollback. The issue is that an exception was caught and the transaction was marked rollback-only, then a commit is attempted.",
      "fail_rate": 0.8,
      "condition": "",
      "sources": []
    },
    {
      "action": "Catching the exception in the outer method and ignoring it",
      "why_fails": "The transaction is already marked rollback-only by the inner method; ignoring the exception does not reset the transaction status.",
      "fail_rate": 0.9,
      "condition": "",
      "sources": []
    },
    {
      "action": "Increasing the transaction timeout to avoid premature rollback",
      "why_fails": "The rollback is due to a data error (e.g., constraint violation), not a timeout. Increasing timeout does not address the root cause.",
      "fail_rate": 0.7,
      "condition": "",
      "sources": []
    }
  ],
  "workarounds": [
    {
      "action": "Use REQUIRES_NEW propagation for the inner method to create a separate transaction: `@Transactional(propagation = Propagation.REQUIRES_NEW)` so that the inner transaction's rollback does not affect the outer transaction.",
      "success_rate": 0.9,
      "how": "Use REQUIRES_NEW propagation for the inner method to create a separate transaction: `@Transactional(propagation = Propagation.REQUIRES_NEW)` so that the inner transaction's rollback does not affect the outer transaction.",
      "condition": "",
      "sources": []
    },
    {
      "action": "Check for rollback-only status before committing: `TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();` and then handle the error gracefully in the outer method by calling `TransactionAspectSupport.currentTransactionStatus().flush()`.",
      "success_rate": 0.85,
      "how": "Check for rollback-only status before committing: `TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();` and then handle the error gracefully in the outer method by calling `TransactionAspectSupport.currentTransactionStatus().flush()`.",
      "condition": "",
      "sources": []
    },
    {
      "action": "Refactor the code to avoid swallowing exceptions: ensure that any exception that triggers a rollback is rethrown to the outer transactional boundary, e.g., `catch (DataIntegrityViolationException e) { throw new RuntimeException(e); }`.",
      "success_rate": 0.8,
      "how": "Refactor the code to avoid swallowing exceptions: ensure that any exception that triggers a rollback is rethrown to the outer transactional boundary, e.g., `catch (DataIntegrityViolationException e) { throw new RuntimeException(e); }`.",
      "condition": "",
      "sources": []
    }
  ],
  "workarounds_zh": [
    "Use REQUIRES_NEW propagation for the inner method to create a separate transaction: `@Transactional(propagation = Propagation.REQUIRES_NEW)` so that the inner transaction's rollback does not affect the outer transaction.",
    "Check for rollback-only status before committing: `TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();` and then handle the error gracefully in the outer method by calling `TransactionAspectSupport.currentTransactionStatus().flush()`.",
    "Refactor the code to avoid swallowing exceptions: ensure that any exception that triggers a rollback is rethrown to the outer transactional boundary, e.g., `catch (DataIntegrityViolationException e) { throw new RuntimeException(e); }`."
  ],
  "transition_graph": {
    "leads_to": [],
    "preceded_by": [],
    "frequently_confused_with": []
  },
  "official_doc_url": "https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/tx-propagation.html",
  "official_doc_section": null,
  "error_code": null,
  "verification_tier": "ai_generated",
  "confidence": 0.87,
  "fix_success_rate": 0.85,
  "resolvable": "true",
  "first_seen": "2024-01-10",
  "last_confirmed": "2024-06-01",
  "last_updated": "2024-06-01",
  "evidence_count": 1,
  "tags": [],
  "locale": "en",
  "aliases": []
}