🚨 𝗧𝘄𝗼 𝗳𝗮𝗶𝗹𝘂𝗿𝗲𝘀 𝗵𝗮𝗽𝗽𝗲𝗻𝗲𝗱. 𝗬𝗼𝘂𝗿 𝗹𝗼𝗴 𝘀𝗵𝗼𝘄𝘀 𝗼𝗻𝗲. Most developers know that try-with-resources closes resources automatically. But many miss this: ⚠️ if the try block fails, and then close() fails too, the close() exception becomes suppressed. And sometimes that second exception is exactly what tells you whether the output can still be trusted. Example 👇 try ( OutputStream out = Files.newOutputStream(path); ZipOutputStream zip = new ZipOutputStream(out) ) { writeEntries(zip); } Now imagine this actually happened: 📌 Primary exception writeEntries(zip) failed 📌 Suppressed exception zip.close() failed At first glance, you may think: ▪ one record failed ▪ export failed ▪ investigate the business/data issue But that is only half the story. Because for resources like ZipOutputStream, close() is not just cleanup. It may still need to: ▪ finish the ZIP structure ▪ flush remaining bytes ▪ write the final directory/footer So the suppressed exception can tell you something critical: 🚫 the output file may be incomplete or corrupted That changes the conclusion. Without the suppressed exception, you may think: ✅ "The export failed because of one bad record." With the suppressed exception, the better conclusion is: ❌ "The ZIP itself may be invalid. Do not trust the file." And here is how teams often hide that second failure: log.error("Export failed: {}", e.getMessage()); Now the log shows only the primary exception. The suppressed one is still there... but easy to miss. You need this: log.error("Export failed", e); And when needed, inspect: e.getSuppressed() 🧠 𝗧𝗵𝗲 𝗿𝗲𝗮𝗹 𝗹𝗲𝘀𝘀𝗼𝗻: The primary exception tells you why the operation failed. The suppressed exception may tell you whether the output can still be trusted. That is a huge difference in production. Especially for: 📦 ZIP / GZIP export 📄 CSV generation 💾 file writing 🌐 response/output streams ☁️ upload streams Miss the suppressed exception - miss half the story. Have you ever found the real operational clue inside getSuppressed()? 🤔 #Java #Backend #Exceptions #JavaIO #SoftwareEngineering #Debugging #CleanCode
Ruslan Mukhamadiarov’s Post
More Relevant Posts
-
Is your @Transactional annotation actually doing what you think? 🧐 In Spring Boot, data integrity is everything. But I often see a common trap: Self-invocation. If you call a transactional method from another method within the same class, the Spring Proxy is bypassed. 📉 The result? No transaction starts, and your data might end up inconsistent without any error message. Check: ✅ The Proxy Rule: Spring uses AOP proxies. External calls go through the proxy; internal calls don't. ✅ The Fix: Move the transactional logic to a separate Service or use AspectJ if complexity scales. ✅ Bonus: Always use readOnly = true for fetch operations to improve performance and avoid unnecessary flush calls. It’s not just about using the framework; it’s about understanding the "Magic" behind it. 🚀 Have you ever faced a "phantom" database bug because of this? Let's swap stories! 👇 hashtag #Java #SpringBoot #Backend #Database #CleanCode #SoftwareEngineering #JavaDeveloper
To view or add a comment, sign in
-
-
The Spring Boot annotation that is silently corrupting your database. If you are a Spring Boot developer, you probably use @Transactional every day. If something fails, the database rolls back. Simple, right? But what happens when you write code like this? @Service public class UserService { // The entry point called by the Controller public void registerUser(UserDTO dto) { // ... some validation logic ... saveUserAndSendEmail(dto); } @Transactional public void saveUserAndSendEmail(UserDTO dto) { userRepository.save(new User(dto.email())); emailService.sendWelcomeEmail(dto.email()); // What if this throws an exception? } } What you think happens: If the email service fails and throws an exception, @Transactional catches it, rolls back the database insert, and the user is not saved. What ACTUALLY happens: The database commits the user anyway. Your system now has a user who never got their welcome email, and your database is in an inconsistent state. Why did it fail? The "Proxy Bypass" Trap. Spring’s @Transactional doesn't work by magic; it works by creating an AOP Proxy around your class. When an outside class (like your Controller) calls your Service, it hits the Proxy first, which opens the database transaction. BUT... if you call a method from within the same class (like registerUser calling saveUserAndSendEmail), you are using the internal this reference. You completely bypassed the Spring Proxy. The transaction never started. The rollback will never happen. The Senior Fixes: 1. The Architecture Fix: Move the @Transactional logic to a separate UserRegistrationService. Calling an external class forces you to go through the proxy. 2. The Simple Fix: Put @Transactional on the entry-point method (registerUser) instead of the internal helper method. Stop assuming annotations are magic. If you don't understand how proxies work under the hood, your data is at risk! Have you ever spent hours debugging a @Transactional rollback that just wouldn't trigger? 👇 #Java #SpringBoot #Hibernate #BackendDevelopment #Microservices #SoftwareEngineering #CleanCode #TechTips #LogicLedaMagic
To view or add a comment, sign in
-
Most transaction bugs in Spring Boot are not SQL bugs—they’re transaction boundary bugs. Today’s focus is a deep dive into @Transactional: propagation, isolation, and rollback rules. If you only use the default settings everywhere, you may accidentally create hidden data inconsistencies or unexpected commits. Example: @Service public class PaymentService { @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class) public void processPayment(Order order) { paymentRepository.save(new Payment(order.getId(), order.getTotal())); inventoryService.reserve(order.getItems()); } } Key idea: REQUIRED joins an existing transaction or starts a new one, REQUIRES_NEW creates a separate one, and isolation controls visibility of concurrent changes. By default, rollback happens for unchecked exceptions, so checked exceptions often need explicit rollbackFor. Treat @Transactional as an architectural decision, not just an annotation. #Java #SpringBoot #BackendDevelopment
To view or add a comment, sign in
-
-
Most transaction bugs in Spring Boot are not SQL bugs—they’re transaction boundary bugs. Today’s focus is a deep dive into @Transactional: propagation, isolation, and rollback rules. If you only use the default settings everywhere, you may accidentally create hidden data inconsistencies or unexpected commits. Example: @Service public class PaymentService { @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class) public void processPayment(Order order) { paymentRepository.save(new Payment(order.getId(), order.getTotal())); inventoryService.reserve(order.getItems()); } } Key idea: REQUIRED joins an existing transaction or starts a new one, REQUIRES_NEW creates a separate one, and isolation controls visibility of concurrent changes. By default, rollback happens for unchecked exceptions, so checked exceptions often need explicit rollbackFor. Treat @Transactional as an architectural decision, not just an annotation. #Java #SpringBoot #BackendDevelopment
To view or add a comment, sign in
-
-
Is your @Transactional annotation actually doing what you think? 🧐 In Spring Boot, data integrity is everything. But I often see a common trap: Self-invocation. If you call a transactional method from another method within the same class, the Spring Proxy is bypassed. 📉 The result? No transaction starts, and your data might end up inconsistent without any error message. Check: ✅ The Proxy Rule: Spring uses AOP proxies. External calls go through the proxy; internal calls don't. ✅ The Fix: Move the transactional logic to a separate Service or use AspectJ if complexity scales. ✅ Bonus: Always use readOnly = true for fetch operations to improve performance and avoid unnecessary flush calls. It’s not just about using the framework; it’s about understanding the "Magic" behind it. 🚀 Have you ever faced a "phantom" database bug because of this? Let's swap stories! 👇 #Java #SpringBoot #Backend #Database #CleanCode #SoftwareEngineering #JavaDeveloper
To view or add a comment, sign in
-
-
#Post8 In the previous post, we learned how to create custom exceptions. Now the next question is 👇 How do we validate incoming request data? That’s where validation comes in 🔥 In Spring Boot, we use @Valid along with validation annotations. Example 👇 public class User { @NotNull private String name; @Min(18) private int age; } Controller: @PostMapping("/user") public User addUser(@Valid @RequestBody User user) { return user; } 👉 If invalid data is sent, Spring automatically triggers validation errors 💡 Common validation annotations: • @NotNull • @NotEmpty • @Size • @Min / @Max 💡 Why use validation? • Prevent invalid data • Improve API reliability • Reduce manual checks Key takeaway: Always validate incoming data to build robust APIs 🚀 In the next post, we will handle these validation errors globally 🔥 #Java #SpringBoot #BackendDevelopment #RESTAPI #LearnInPublic
To view or add a comment, sign in
-
How I improved API performance by ~40% 🚀 Problem: Slow response time due to heavy DB queries What I changed: • Optimized SQL queries • Added indexing • Reduced unnecessary joins • Used proper pagination Result: Faster APIs Better user experience Most performance issues are not in code, they’re in the database. #Backend #Java #Performance #Microservices #TechTips
To view or add a comment, sign in
-
🚨 One of the most dangerous Spring Boot traps — silent data loss with zero errors. @Transactional on a private method does absolutely nothing. No exception. No warning. Just broken data. ❌ Broken: @Service public class OrderService { public void placeOrder(Order order) { saveOrder(order); } @Transactional // ← silently ignored! private void saveOrder(Order order) { orderRepo.save(order); auditRepo.save(new AuditLog(order)); } } Why does this happen? Spring wraps beans in a proxy to intercept @Transactional calls. But private methods are invisible to the proxy — the call goes direct, completely bypassing transaction management. Result → partial saves, missing audit logs, inconsistent state. The fix: Keep transactional methods public. ✅ Fixed: @Service public class OrderService { @Transactional // ← proxy intercepts correctly public void saveOrder(Order order) { orderRepo.save(order); auditRepo.save(new AuditLog(order)); } } What makes this a production nightmare: → Unit tests pass cleanly → Logs show no errors → Only caught when data is already missing Spring won't warn you. The annotation just silently does nothing. Save this before it saves you. 🔖 Know any other silent Spring Boot traps? Drop them below 👇 #SpringBoot #Java #BackendDevelopment #SoftwareEngineering #CleanCode
To view or add a comment, sign in
-
-
Yesterday I talked about what a broken bug pipeline looks like. Today, here's exactly how I built the fix. And the one database decision that made it 40% faster. 🧵 The goal was simple: Build a system where clients raise bugs, developers fix them, and everyone has exactly the information they need, nothing more, nothing less. That last part is the hard part. Decision 1 - Role-Based Access Control (RBAC) I split the system into two worlds: Client view → raise tickets, track status, add comments Developer view → claim bugs, update progress, resolve tickets Neither can touch what the other owns. Every endpoint is locked behind Spring Security + JWT validation. If you're not authenticated with the right role, you're not getting in. Decision 2 - The database problem nobody talks about Early versions of the system were slow. A single bug record needed: → Bug details → Assigned developer → Client who raised it → All comments Each one was a separate query. 10 bugs on a page = 40+ database hits. This is the N+1 query problem. It's silent, it's common, and it kills performance at scale. The fix: Many-to-one relational mapping in MySQL. Instead of fetching each relationship separately, I restructured the schema so JPA/Hibernate resolves everything in a single optimised JOIN. Result → query response time dropped from ~500ms to ~300ms. That's a 40% reduction. On every single page load. Decision 3 - Docker for deployment I containerised the entire stack. Frontend. Backend. Database. One command. Runs identically everywhere. No "works on my machine" conversations. No environment mismatches between dev and production. What I learned building this: Performance isn't a feature you add at the end. Security isn't a layer you bolt on after launch. Both need to be designed in from line one. The full project end-to-end breakdown is coming in Post 3. I'll show the complete architecture, the tech stack, and what I'd do differently. Follow along 🔔 #Java #SpringBoot #MySQL #Docker #SystemDesign #BackendDevelopment #BuildInPublic #SDE2026 #DatabaseOptimization #SpringSecurity
To view or add a comment, sign in
-
-
Your transaction works perfectly… ✅ Until you call 𝗮𝗻𝗼𝘁𝗵𝗲𝗿 𝗺𝗲𝘁𝗵𝗼𝗱 inside it. Suddenly things behave… differently. Why? 𝗣𝗿𝗼𝗽𝗮𝗴𝗮𝘁𝗶𝗼𝗻. If you’re using `@Transactional` and not thinking about propagation, you’re basically saying: “Spring… you decide.” So what is propagation? It defines how a transaction behaves when one method calls another. Simple idea. But huge impact. Let’s break it down with real-world scenarios 🔹 REQUIRED (default) “Join if exists, else create” 💡 Example: Placing an order → Payment service called Both run in the "same transaction". If payment fails → everything rolls back. 🔹 REQUIRES_NEW “Always start fresh” 💡 Example: Order fails ❌ But you still want to "log the failure" Logging runs in a separate transaction → it gets saved ✅ 🔹 SUPPORTS “Join if exists, else run without transaction” 💡 Example: Fetching optional audit data Transaction or not… it doesn’t care. 🔹 NOT_SUPPORTED “Run without transaction” 💡 Example: Heavy read operation where transaction overhead is unnecessary Suspends existing transaction ⏸️ 🔹 MANDATORY “Transaction must exist” 💡 Example: Critical financial operation If no transaction → throw error 🚨 🔹 NEVER “Transaction must NOT exist” 💡 Example: A method that should never be part of a transaction If one exists → exception 💥 🔹 NESTED “Transaction inside a transaction” 💡 Example: Partial rollback scenario Inner transaction fails → outer can still continue Here’s the real insight Most bugs in transaction handling don’t come from syntax… They come from 𝘄𝗿𝗼𝗻𝗴 𝗽𝗿𝗼𝗽𝗮𝗴𝗮𝘁𝗶𝗼𝗻 choices. Using `@Transactional` is easy. Using it correctly is what makes you a solid backend developer. Next time you add `@Transactional`, don’t stop there… Ask: “How should this transaction behave?” #CoreJava #SpringBoot #JavaDeveloper #Transactional #BackendDevelopment #SoftwareEngineering #Developers #Programming #Developers #RDBMS #SQL #JPA #Hibernate #Database #Microservices #aswintech #SystemDesign
To view or add a comment, sign in
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