{"id":23034824,"url":"https://github.com/m-thirumal/spring-boot-transaction","last_synced_at":"2025-09-09T23:19:05.967Z","repository":{"id":258549777,"uuid":"860778563","full_name":"m-thirumal/spring-boot-transaction","owner":"m-thirumal","description":"Spring Boot Transaction Propagation and Isolation","archived":false,"fork":false,"pushed_at":"2024-10-17T10:39:35.000Z","size":16,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-08T12:46:18.974Z","etag":null,"topics":["commit","database","isolation","propagation","rollback","transaction"],"latest_commit_sha":null,"homepage":"https://m-thirumal.github.io/spring-boot-transaction/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/m-thirumal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-21T06:28:48.000Z","updated_at":"2024-10-17T10:41:52.000Z","dependencies_parsed_at":"2024-10-19T14:29:33.555Z","dependency_job_id":null,"html_url":"https://github.com/m-thirumal/spring-boot-transaction","commit_stats":null,"previous_names":["m-thirumal/spring-boot-transaction"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m-thirumal%2Fspring-boot-transaction","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m-thirumal%2Fspring-boot-transaction/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m-thirumal%2Fspring-boot-transaction/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m-thirumal%2Fspring-boot-transaction/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/m-thirumal","download_url":"https://codeload.github.com/m-thirumal/spring-boot-transaction/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246900435,"owners_count":20852053,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["commit","database","isolation","propagation","rollback","transaction"],"created_at":"2024-12-15T16:36:07.826Z","updated_at":"2025-09-09T23:19:05.941Z","avatar_url":"https://github.com/m-thirumal.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spring boot Transaction\n\nA `transaction` is a sequence of multiple statements that must either `all succeed or all fail`. If one step fails, everything gets `rolled back`.\n\nThe Transaction is used to keep our data `consistent` in the database.\n\n## ACID Properties\n\n* `A — Atomicity:` All or nothing.\n    If any part fails, the whole transaction is rolled back.\n* `C — Consistency:` Rules Respected\n    Your database should always stay valid — it should move from one valid state to another.\n* `I — Isolation:` Do it like you are alone\n    Multiple transactions shouldn’t interfere with each other.\n* `D — Durability:` Written in Stone\n    Once the transaction is committed, the changes are permanent, even if the system crashes.\n\nSpring’s `@Transactional` is responsible for transaction boundaries\n\n* Starting a transaction before your method runs\n* Committing it if the method completes successfully\n* Rolling back if a runtime exception is thrown\n\n## How does Spring work internally?\n\nSpring uses `AOP (Aspect-Oriented Programming)` to wrap your service method in extra behavior — in this case, transaction management.\n\nWhen your service is marked with `@Transactional`, Spring does the following:\n\n    Creates a proxy around your class or method\n    When a method is called:\n    — It begins a transaction\n    — Runs your business logic\n    — Commits or rolls back based on success or failure\n\n    Spring uses:\n    — `JDK Dynamic Proxies` if your class implements an interface `CGLIB proxies` if it doesn’t\n\nThis allows Spring to manage transactions without modifying your core logic.\n\nNow,\n\n    💡 Clear and clean business logic\n    🔄 Reusable, declarative transaction control\n    🛡 Safe rollback on exceptions\n    📦 Less boilerplate, more focus\n\n## Where Can You Add `@Transactional`?\n\nYou can use it in two ways:\n\n### Method Level\n\nAdd `@Transactional` on top of a `public` method. Only public methods can be proxied by Spring. If you add it to `private or protected` methods, it `won’t work`, because Spring can’t create proxies for them.\n\n### Class Level\n\nAdd `@Transactional` At the class level, Spring will apply it to all public methods within that class.\n\nBy default, Spring rolls back only for unchecked exceptions (subclasses of RuntimeException or Error).\n\nIf your method throws a checked exception, the transaction will not be rolled back — unless you explicitly configure it:\n```java\n@Transactional(rollbackFor = Exception.class)\n```\n## Propogations\n\n* Required (default): My method needs a transaction, either open one for me or use an existing one → getConnection(). setAutocommit(false). commit().\n\n* Supports: I don’t really care if a transaction is open or not, i can work either way → nothing to do with JDBC\n\n* Mandatory: I’m not going to open up a transaction myself, but I’m going to cry if no one else opened one up → nothing to do with JDBC\n\n* Require_new: I want my completely own transaction → getConnection(). setAutocommit(false). commit().\n\n* Not_Supported: I really don’t like transactions, I will even try and suspend a current, running transaction → nothing to do with JDBC\n\n* Never: I’m going to cry if someone else started up a transaction → nothing to do with JDBC\n\n* Nested: It sounds so complicated, but we are just talking savepoints! → connection.setSavepoint()\n\n\n## Common Pitfall\n\n1. ⚠️ Placing `@Transactional` on `Private` or `Static` Methods (or constructors)\nSpring manages transactions via AOP proxies, which don’t intercept private or static methods.\n\n```java\n@Transactional\nprivate void internalMethod() { // ⚠️ NOT TRANSACTIONAL!\n // Spring won't manage transactions here`\n}\n```\n✔ Fix: Always use @Transactional on public methods.\n\n2. ⚠️ Nested Transactions Can Cause Unexpected Rollbacks\nBy default, @Transactional rolls back the entire transaction if one operation fails.\nIf you need partial rollbacks, use Propagation.REQUIRES_NEW.\nExample:\n\n```java\n@Transactional(propagation = Propagation.REQUIRES_NEW)\npublic void logTransaction(String message) {\n transactionRepository.save(new TransactionLog(message));\n}\n```\n✔ Ensures log entry is saved even if the main transaction fails.\n\n3. ⚠️ Not Configuring Rollback for Specific Exceptions\nBy default, @Transactional only rolls back unchecked exceptions (RuntimeException), not checked exceptions.\nExample (Won’t Rollback):\n\n```java\n@Transactional\npublic void processOrder() throws Exception { // ⚠️ Checked Exception won't trigger rollback\n throw new Exception(\"Processing failed!\");\n}\n```\n✔ Fix: Explicitly specify rollback behavior.\n\n```java\n@Transactional(rollbackFor = Exception.class)\npublic void processOrder() throws Exception {\n throw new Exception(\"Processing failed!\");\n}\n```\n4. ⚠️ Mixing `@Transactional` with Asynchronous `(@Async)` Methods\nIf you use `@Async`, Spring executes the method in a separate thread, causing `@Transactional to lose its context.\nExample:\n\n```java\n@Async\n@Transactional\npublic void processData() {\n // ⚠️ Transaction won’t apply correctly here\n}\n```\n✔ Fix: Use `@Transactional` only in synchronous methods.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fm-thirumal%2Fspring-boot-transaction","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fm-thirumal%2Fspring-boot-transaction","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fm-thirumal%2Fspring-boot-transaction/lists"}