You have two @Transactional methods. The outer service calls the inner one. The inner method fails, but you want to handle the error and continue the outer transaction. Why does the whole thing roll back by default? This isn't a bug. It's Spring's transaction propagation. By default, Spring uses `Propagation.REQUIRED`. This means if a transaction already exists, the inner method just joins it. They become one single unit of work. If any part fails, the whole thing is marked for rollback. Simple and safe. But what if that inner method *must* succeed on its own? Think of logging a critical audit record. That's when you use `Propagation.REQUIRES_NEW`. This tells Spring to pause the current transaction and start a completely new, independent one. This new transaction can commit or fail on its own, without affecting the outer one. The audit log gets saved even if the main operation later rolls back. The trade-off? Performance. `REQUIRES_NEW` is more resource-intensive because it often requires a separate database connection. So don't use it everywhere. Reserve it for specific, independent tasks where a separate outcome is essential. Understanding the difference gives you precise control. #Java #SpringBoot #SoftwareDevelopment #BackendDevelopment #SpringFramework #Transactions #SystemDesign #DeveloperTips
Spring Transaction Propagation: REQUIRED vs REQUIRES_NEW
More Relevant Posts
-
🧠 Spring @Transactional – Why Your Rollback Didn’t Happen This is one of the most dangerous “it works… until it doesn’t” scenarios in Spring. You mark a method with @Transactional. You throw an exception. You expect a rollback. But nothing rolls back. And you don’t notice… until production. ❌ The Problem: Self-Invocation In Spring, @Transactional works through proxies. When a method inside the same class calls another @Transactional method using this.method(), 👉 it bypasses the proxy. 👉 no interception happens. 👉 no transactional behavior is applied. In the image above: updateUser() calls this.sendEmail() That internal call never goes through Spring’s proxy. If sendEmail() fails? The save operation may NOT roll back. Silent failure. No warning. ✅ The Fix: Go Through the Proxy Instead of calling the method directly: Use self-injection Or move the transactional logic to a separate service When you call through the injected proxy (self.sendEmail()), Spring can properly intercept the call and apply transactional behavior. Now your rollback works as expected. 🎯 The Real Lesson Transactions are not just annotations. They are proxy-driven runtime behavior. If you don’t understand how Spring AOP works under the hood, you’ll eventually debug this at 2 AM. Have you ever been bitten by self-invocation in Spring? Let’s hear your story 👇 #Java #SpringBoot #SpringFramework #Transactional #SoftwareArchitecture #CleanCode #JavaDevelopment #BackendDevelopment
To view or add a comment, sign in
-
-
Why Doesn’t Rollback Happen in Self-Invocation with @Transactional? You annotate a method with @Transactional. An exception occurs. You expect a rollback. But the data is still committed. If this happens in Spring Framework, one common reason is self-invocation. What Is Self-Invocation? Self-invocation happens when a method inside a class calls another method of the same class. At first glance, this seems perfectly fine. But here’s the hidden problem. Why Rollback Doesn’t Happen: Spring applies @Transactional using a proxy mechanism. -When a method is called from outside the class, the call goes through Spring’s proxy. -The proxy starts the transaction and manages rollback. However, when a method calls another method inside the same class: -The call happens directly within the object. -It bypasses Spring’s proxy. -Spring never intercepts the call. -The transaction is never started. And if no transaction was started, rollback cannot happen. The Real Reason: Rollback doesn’t fail because of the exception. Rollback fails because Spring never got the chance to manage that internal method call. No proxy interception → No transaction → No rollback. Key Takeaway: @Transactional is not just an annotation. It works only when the method call goes through Spring’s proxy. #Java #SpringBoot #SpringFramework #BackendDevelopment #SoftwareEngineering #Microservices #AOP #Transactional
To view or add a comment, sign in
-
-
𝗢𝗻𝗲 𝗦𝗽𝗿𝗶𝗻𝗴 𝗔𝗻𝗻𝗼𝘁𝗮𝘁𝗶𝗼𝗻 𝗧𝗵𝗮𝘁 𝗖𝗮𝗻 𝗦𝗮𝘃𝗲 — 𝗼𝗿 𝗕𝗿𝗲𝗮𝗸 — 𝗬𝗼𝘂𝗿 𝗔𝗽𝗽 @Transactional looks harmless. Add it to a method. Your data becomes “safe”. Until it doesn’t. Here’s what actually happens when Spring sees @Transactional: ➡️ Spring creates a proxy around your class ➡️ The proxy opens a transaction before the method runs ➡️ Your method executes ➡️ If it completes successfully → COMMIT ➡️ If a runtime exception occurs → ROLLBACK So far, so good. But here’s the catch 👇 Transactions only work when the call goes through the proxy. That means this breaks transactions silently: ❌ A method calling another @Transactional method inside the same class (self-invocation) Why? Because the call never leaves the object — the proxy is bypassed. No proxy → no transaction → no rollback. Another common surprise: 🔸 By default, Spring rolls back only on unchecked exceptions 🔸 Checked exceptions will still COMMIT unless configured And one more: 🔸 @Transactional belongs at service boundaries, not controllers, not repositories, not everywhere. When used correctly, @Transactional gives you: ✅ Consistent data ✅ Clear business boundaries ✅ Safe rollback behavior When misunderstood, it creates: ❌ Phantom bugs ❌ Partial writes ❌ False confidence My rule of thumb: If you can’t explain how @Transactional works internally, you probably shouldn’t use it yet. If you had to debug one issue caused by @Transactional, what was it? 👇 Let’s learn from each other. #SpringBoot #Java #Transactional #BackendDevelopment #SoftwareArchitecture #SpringFramework
To view or add a comment, sign in
-
🚨 Why your @Transactional might NOT work in Spring Boot This is a common mistake that can silently break your code. In Spring Boot, @Transactional does not work everywhere automatically. Spring uses a proxy to start and manage transactions. Here’s the catch 👇 ❌ If a method calls another @Transactional method inside the same class, the transaction will NOT start. public void placeOrder() { saveOrder(); // @Transactional — but no transaction here } Why does this happen? Spring starts a transaction only when a method is called from outside the class. Self-invocation bypasses Spring’s proxy completely. So you get: No transaction No error No warning Everything looks fine, but it can lead to partially saved data. ✅ How to fix it: Move the @Transactional method to another service (bean) Keep transactional logic in a separate class If you’re using Spring Boot and @Transactional, this is worth remembering. #springboot #java #transactions
To view or add a comment, sign in
-
Your code throws an exception… logs show failure… and the DB still commits. At first it feels like Spring is broken. But it’s not. In Spring’s @Transactional, rollback is not based on “an exception happened” - it depends on which exception type goes out of the transactional method. By default: Unchecked exceptions (RuntimeException) - rollback happens Checked exceptions (Exception) → transaction commits This part confused me a lot earlier. Because as a developer, I was thinking- exception means failure, right? But Spring treats checked exceptions as something expected. Like business-level issues, not system failure. Internally it’s just a proxy watching the method exit. If runtime exception goes out - rollback. If checked exception goes out - Spring thinks “ok, you handled it”. @Transactional public void placeOrder() throws Exception { saveOrder(); throw new Exception("payment timeout"); } Even here, transaction commits. To force rollback, we have to say it clearly: @Transactional(rollbackFor = Exception.class) Once I understood this, many “random commit” issues started making sense. #Java #backend #transactions
To view or add a comment, sign in
-
Moving from "It works on my machine" to "It works in production." 🚀 I used to think backend development was just about writing Controllers and Services. But recently, I realized that building is only half the job. The real engineering happens when you ensure your code doesn't break. I built a dedicated Spring Boot Testing Playground to master the "Testing Pyramid" hands-on. Instead of just writing a basic API, I focused entirely on reliability. 🧪 My Testing Strategy: JUnit 5 (The Logic): For validating simple utility logic instantly. Mockito (The Speed): I learned how to mock the Database layer to test Business Logic in isolation. (No more slow DB calls during unit tests!) RestAssured (The Reality): For spinning up the full context and testing endpoints like a real user. It’s a simple Task Manager API on the surface, but under the hood, it’s a blueprint for writing fault-tolerant Java applications. #Java #SpringBoot #BackendDevelopment #Testing #Mockito #RestAssured #Engineering
To view or add a comment, sign in
-
-
We all use @Transactional. But what actually handles the commit and rollback? Spring doesn’t magically modify your method. It wraps your bean in a proxy. So the real flow is: Client → Proxy → TransactionManager → Your Logic → Commit / Rollback What the proxy basically does: • Start transaction (autoCommit = false) • Bind connection to current thread (ThreadLocal) • Execute your method • If everything’s fine → commit • If RuntimeException happens → rollback Small but important detail: By default, Spring does not roll back on checked exceptions. And that’s usually where “why didn’t this rollback?” bugs come from. Understanding proxy-based transactions helps you debug: • Self-invocation issues • Async breaking transactions • Unexpected commits in prod Using @Transactional is easy. Knowing what’s happening behind it? That’s real backend depth. #SpringBoot #Java #BackendEngineering
To view or add a comment, sign in
-
🔥 @Transactional in Spring Boot – Simple to use, easy to misuse Almost every Spring Boot project uses @Transactional, but many production bugs happen because it’s not fully understood. 👉 What @Transactional actually does • Groups multiple DB operations into one transaction • Commits if everything succeeds • Rolls back if an exception occurs 👉 Common mistakes developers make ❌ Assuming it works on private methods ❌ Self-invocation (method calling another method in same class) ❌ Not knowing rollback happens only for unchecked exceptions by default ❌ Using it blindly without understanding propagation 👉 Important concepts to know ✅ Propagation types (REQUIRED, REQUIRES_NEW) ✅ Rollback rules ✅ Transaction boundaries 💡 Real lesson: If you don’t understand transactions, your data consistency is at risk — even if your code compiles perfectly. #SpringBoot #Java #Transactional #JPA #Hibernate #BackendDevelopment #Microservices #SoftwareEngineering
To view or add a comment, sign in
-
𝗗𝗮𝘆 𝟰𝟰/𝗻 - 𝗜𝗻𝘁𝗲𝗴𝗿𝗮𝘁𝗶𝗼𝗻 𝘁𝗲𝘀𝘁𝘀 𝗺𝗮𝘁𝘁𝗲𝗿 𝗺𝗼𝗿𝗲 𝘁𝗵𝗮𝗻 𝗽𝗲𝗿𝗳𝗲𝗰𝘁 𝘂𝗻𝗶𝘁 𝘁𝗲𝘀𝘁𝘀 As systems grow, confidence doesn’t come from how many tests we write; it comes from what those tests actually validate. In 𝗝𝗮𝘃𝗮 𝗯𝗮𝗰𝗸𝗲𝗻𝗱 𝘀𝘆𝘀𝘁𝗲𝗺𝘀, one of the most valuable layers is the integration test. It sits between fast unit tests and expensive end-to-end tests, and it answers a critical question: Does my code work with the real infrastructure it depends on? The 𝗰𝗼𝗱𝗲 below represents a common and effective pattern in modern Spring Boot projects. Instead of mocking the database, the test spins up a real 𝗣𝗼𝘀𝘁𝗴𝗿𝗲𝗦𝗤𝗟 instance in a container and verifies the repository behavior against it. This approach helps catch issues that unit tests can’t: configuration mistakes, SQL mismatches, schema problems, and unexpected behavior across layers. It keeps feedback fast while still being close to production reality, which is exactly what reliable 𝗖𝗜/𝗖𝗗 𝗽𝗶𝗽𝗲𝗹𝗶𝗻𝗲𝘀 need. Back again tomorrow on 𝗗𝗮𝘆 𝟰𝟱/𝗻. #Day44 #Java #SpringBoot #TestingStrategy #FullStackDeveloper #BackendEngineering #LearningInPublic #Consistency
To view or add a comment, sign in
-
-
Most developers write code. Few developers design for failure. Designing for failure means building systems that remain stable even when things go wrong. In real production systems, failures are normal: • External API timeouts • Database connection issues • Invalid user input • Network failures If exceptions are not handled properly, your system will crash — not scale. Crash means: • Sudden 500 errors • Application restarts • Broken user experience Scale means: • Handling more users smoothly • Recovering from failures gracefully • Staying stable under high traffic In Java + Spring Boot, good exception handling means: ✔️ Using @ControllerAdvice for global handling ✔️ Returning meaningful HTTP status codes ✔️ Logging errors properly ✔️ Never exposing internal stack traces Clean exception handling = Stable production systems. What’s the biggest production issue you’ve faced? 👇 #Java #SpringBoot #BackendDevelopment #Microservices #SoftwareEngineering
To view or add a comment, sign in
More from this author
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development