|
| 1 | +{ |
| 2 | + "id": 104, |
| 3 | + "slug": "manual-transaction-vs-declarative", |
| 4 | + "title": "Manual JPA Transaction vs Declarative @Transactional", |
| 5 | + "category": "enterprise", |
| 6 | + "difficulty": "intermediate", |
| 7 | + "jdkVersion": "11", |
| 8 | + "oldLabel": "Java EE", |
| 9 | + "modernLabel": "Jakarta EE 8+", |
| 10 | + "oldApproach": "Manual Transaction", |
| 11 | + "modernApproach": "@Transactional", |
| 12 | + "oldCode": "@PersistenceContext\nEntityManager em;\n\npublic void transferFunds(Long from, Long to,\n BigDecimal amount) {\n EntityTransaction tx = em.getTransaction();\n tx.begin();\n try {\n Account src = em.find(Account.class, from);\n Account dst = em.find(Account.class, to);\n src.debit(amount);\n dst.credit(amount);\n tx.commit();\n } catch (Exception e) {\n tx.rollback();\n throw e;\n }\n}", |
| 13 | + "modernCode": "@ApplicationScoped\npublic class AccountService {\n @PersistenceContext\n EntityManager em;\n\n @Transactional\n public void transferFunds(Long from, Long to,\n BigDecimal amount) {\n Account src = em.find(Account.class, from);\n Account dst = em.find(Account.class, to);\n src.debit(amount);\n dst.credit(amount);\n }\n}", |
| 14 | + "summary": "Replace verbose begin/commit/rollback blocks with a single @Transactional annotation.", |
| 15 | + "explanation": "Manual transaction management requires explicit begin(), commit(), and rollback() calls wrapped in try-catch blocks — every service method repeats this boilerplate. The @Transactional annotation delegates lifecycle management to the container: it begins a transaction before the method, commits on success, and rolls back on RuntimeException automatically.", |
| 16 | + "whyModernWins": [ |
| 17 | + { |
| 18 | + "icon": "🗑️", |
| 19 | + "title": "No boilerplate", |
| 20 | + "desc": "One annotation replaces repetitive begin/commit/rollback try-catch blocks." |
| 21 | + }, |
| 22 | + { |
| 23 | + "icon": "🛡️", |
| 24 | + "title": "Safer rollback", |
| 25 | + "desc": "The container guarantees rollback on unchecked exceptions — no risk of forgetting the catch block." |
| 26 | + }, |
| 27 | + { |
| 28 | + "icon": "📐", |
| 29 | + "title": "Declarative control", |
| 30 | + "desc": "Propagation, isolation, and rollback rules are expressed as annotation attributes." |
| 31 | + } |
| 32 | + ], |
| 33 | + "support": { |
| 34 | + "state": "available", |
| 35 | + "description": "Widely available since Jakarta EE 8 / Java 11" |
| 36 | + }, |
| 37 | + "prev": "enterprise/jndi-lookup-vs-cdi-injection", |
| 38 | + "next": "enterprise/soap-vs-jakarta-rest", |
| 39 | + "related": [ |
| 40 | + "enterprise/ejb-vs-cdi", |
| 41 | + "enterprise/jdbc-vs-jpa", |
| 42 | + "enterprise/jpa-vs-jakarta-data" |
| 43 | + ], |
| 44 | + "docs": [ |
| 45 | + { |
| 46 | + "title": "Jakarta Transactions Specification", |
| 47 | + "href": "https://jakarta.ee/specifications/transactions/" |
| 48 | + }, |
| 49 | + { |
| 50 | + "title": "Jakarta Transactions 2.0 API", |
| 51 | + "href": "https://jakarta.ee/specifications/transactions/2.0/apidocs/" |
| 52 | + } |
| 53 | + ] |
| 54 | +} |
0 commit comments