🔐 Optimistic vs Pessimistic Locking – When to Use What? In concurrent systems, multiple users may try to update the same data at the same time. To handle this, we use locking mechanisms: 🔹 Optimistic Locking ✔ Assumes conflicts are rare ✔ No lock while reading ✔ Uses versioning (e.g., @Version in JPA) ✔ If conflict occurs → transaction fails & retries 🔹 Pessimistic Locking ✔ Assumes conflicts are frequent ✔ Locks the resource before update ✔ Prevents other transactions from accessing it ✔ Can lead to blocking or deadlocks 📌 Key Insight: Use Optimistic Locking for high-read, low-write systems Use Pessimistic Locking when data consistency is critical Choosing the right locking strategy is crucial for performance and data integrity. #Java #BackendDeveloper #Database #JPA #Hibernate #Concurrency #SystemDesign #SoftwareEngineering #TechLearning #Developers
Optimistic vs Pessimistic Locking: Choosing the Right Strategy
More Relevant Posts
-
Another day, another `StaleObjectStateException`. But this time… let’s look at it from an Architect’s lens. In distributed systems, failures are loud. But **data conflicts are silent… until they aren’t.** This exception is not noise. It’s a **signal of competing realities** inside your system. --- 🔍 What actually happened? Two independent flows believed: 👉 “I have the latest state.” Only one was right. Hibernate, through **optimistic locking**, enforces a simple rule: > *“You can only update what you truly own — version included.”* When that assumption breaks → **`StaleObjectStateException` is thrown.** --- 🏗️ **Architectural Insight** This is not just about ORM. This is about **concurrency design decisions**: * Are we allowing **parallel writes** on the same aggregate? * Do we understand **transaction boundaries** clearly? * Are we mixing **sync + async updates** without coordination? * Is our system **eventually consistent… or accidentally inconsistent?** --- ⚠️ **Where systems go wrong** * Treating DB rows as isolated records instead of **domain aggregates** * Ignoring **versioning strategy** * Designing APIs without **idempotency** * Overusing long-running transactions * Missing **conflict resolution strategy** --- 🛠️ **Architect-level thinking** ✔️ Model strong **aggregate boundaries** ✔️ Use `@Version` not as annotation, but as a **contract** ✔️ Embrace **retry + reconciliation patterns** ✔️ Prefer **event-driven updates** where contention is high ✔️ Design APIs to be **idempotent and conflict-aware** --- 💭 The real lesso `StaleObjectStateException` is not a Hibernate problem. It’s a **design conversation your system is forcing you to have. Ignore it → you get silent data corruption. Respect it → you build resilient, concurrent systems. Concurrency is not an edge case. It is the system. #Architecture #SystemDesign #Concurrency #Java #Hibernate #DistributedSystems
To view or add a comment, sign in
-
🚨Application is running in production and appears to be working properly. However, even when there are no API calls or incoming requests, it still results in an OutOfMemory(OOM) error. 👉Memory Leak Objects are created but never deleted - memory fills up slowly over time 👉 Background Jobs Scheduled tasks run silently on timer - not on user requests. They consume memory 24/7. 👉Cron Jobs Cron jobs are fire at fixed intervals - every minute, hour, or day. Each run can load large data into memory and never release it if not handled properly. 👉JVM Schedulers Internal JVM schedulers like ScheduledExecutorService, Timer, and TimeTask run completely inside the JVM. If tasks are registered without cancellation and shutdown, they hold memory reference silently 👉Too Many Threads Each thread eats 1MB of RAM. 1000 idle threads = nearly 1 GB gone - no traffic needed. 👉Cache Has No Limit Your cache keeps storing data but never removes old entries - it grows forever. 👉 Logging Buffers Async loggers hold messages in a queue. If it fills up, it eats your memory. 👉Wrong JVM / Container Configuration JVM asks for 3GB , Container only has 2.5GB - when your app tried to go beyond 2.5, the OS kills your process or application silently ➡️How to Overcome Memory Leaks -> heap dump analysis Background Jobs -> use try-finally cleanup Cron Jobs -> batch processing JVM Schedulers -> shutdown on app exit Threads -> use fixed thread pool size Cache -> configure time to live on every cache Logging -> bounded async queue JVM Config -> match heap to container size 🎯"Memory doesn't need traffic to leak - it just needs time." #OutOfMemory #MemoryLeak #Java #JVM #JavaDeveloper #ProductionIssues #Microservices #Debugging
To view or add a comment, sign in
-
The N+1 problem happens when your application fetches a list of entities with one query, but then triggers an additional query for each item when accessing related data—often due to lazy loading in ORMs like JPA. What looks like a simple loop in code can result in dozens or hundreds of database calls, increasing latency, stressing the connection pool, and degrading performance under load. It’s not a logic bug but a data access design issue, where the way data is fetched doesn’t match how it’s used, causing the system to quietly slow down as scale increases #Java #SpringBoot #JPA #Hibernate #SystemDesign #Performance #BackendEngineering #Microservices #SoftwareEngineering #Scalability 🔥 Your loop has 1 line → Your database executes 100 queries ⚠️ Works perfectly in dev → Breaks silently under real traffic 📉 Not a logic bug → A hidden data access design flaw 🚨 Lazy loading = invisible performance killer 🧠 N+1 is not a loop problem → It’s a query shape problem 🔥 One-Line Takeaway Your loop didn’t break performance. Your data access pattern did.
To view or add a comment, sign in
-
-
𝗛𝗶𝗴𝗵 𝗣𝗲𝗿𝗳𝗼𝗿𝗺𝗮𝗻𝗰𝗲 𝗠𝗶𝗰𝗿𝗼𝘀𝗲𝗿𝘃𝗶𝗰𝗲 Modern systems must handle high traffic, low latency, and efficient resource usage. Achieving this is not about one technique, but a combination of multiple performance optimizations across layers. I built a 𝗛𝗶𝗴𝗵 𝗣𝗲𝗿𝗳𝗼𝗿𝗺𝗮𝗻𝗰𝗲 𝗠𝗶𝗰𝗿𝗼𝘀𝗲𝗿𝘃𝗶𝗰𝗲 to demonstrate how different techniques work together to improve system performance and scalability. 𝗞𝗲𝘆 𝗽𝗲𝗿𝗳𝗼𝗿𝗺𝗮𝗻𝗰𝗲 𝗼𝗽𝘁𝗶𝗺𝗶𝘇𝗮𝘁𝗶𝗼𝗻𝘀 𝗶𝗺𝗽𝗹𝗲𝗺𝗲𝗻𝘁𝗲𝗱 • Multi-level caching (Caffeine + Redis) to reduce DB load • Database optimization using indexes and projection queries • Keyset pagination for efficient large dataset handling • Parallel processing using Mono.zip for faster aggregation • Bulk operations to reduce DB round trips • Backpressure handling for large data streams • Async logging to avoid blocking request threads • Cache warm-up to eliminate cold start latency • Connection pooling and resource optimization • GZIP compression to reduce network overhead • Correlation ID for request tracing 𝗣𝗲𝗿𝗳𝗼𝗿𝗺𝗮𝗻𝗰𝗲 𝘁𝗲𝘀𝘁𝗶𝗻𝗴 Validated using k6 under different scenarios: • Load testing (normal traffic) • Stress testing (breaking point) • Spike testing (sudden traffic burst) • Soak testing (long-running stability) • Cache performance validation • Pagination performance comparison • Write performance under load 𝗔𝗿𝗰𝗵𝗶𝘁𝗲𝗰𝘁𝘂𝗿𝗲 𝗮𝗽𝗽𝗿𝗼𝗮𝗰𝗵 Controller → Service → Cache → Repository → Database • Layered architecture • Optimized data flow • Reduced unnecessary processing • Designed for high throughput 𝗧𝗲𝗰𝗵 𝗦𝘁𝗮𝗰𝗸 • Java 21 • Spring Boot • Spring WebFlux • Project Reactor (Mono, Flux) • R2DBC (Reactive DB access) • PostgreSQL • Redis (Reactive) - L2 Cache • Caffeine - L1 Cache • Maven • k6 (Performance Testing) This project shows how combining caching, database optimization, efficient queries, and proper architecture leads to a truly high-performance system. Source Code: https://lnkd.in/gdK3Yu6V "Performance is built through design, not afterthought optimization." #Java #Spring #Microservices #BackendDevelopment #HighPerformance #SystemDesign
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! 👇 hashtag #Java #SpringBoot #Backend #Database #CleanCode #SoftwareEngineering #JavaDeveloper
To view or add a comment, sign in
-
-
💡 𝐒𝐩𝐫𝐢𝐧𝐠 𝐃𝐚𝐭𝐚 𝐄𝐧𝐯𝐞𝐫𝐬 - 𝐚𝐮𝐝𝐢𝐭𝐢𝐧𝐠 𝐰𝐢𝐭𝐡𝐨𝐮𝐭 𝐭𝐡𝐞 𝐨𝐯𝐞𝐫𝐡𝐞𝐚𝐝 👉 Spring Data Envers adds automatic change tracking for your entities. ⚙️ Built on top of Hibernate Envers and seamlessly integrates with Spring Data JPA. ⁉️ What it gives you: ✔️ Full history of entity changes ✔️ Who changed what and when ✔️ Access to any previous state ✔️ Built-in versioning (revisions) ⚡ Minimal setup: @Entity @Audited public class User { @Id private Long id; private String name; } ➡️ Every change = new revision stored automatically 🚀 Use it when: ▪️ Audit logs (finance, security) ▪️ Versioning / history tracking ▪️ Rollbacks to previous states ▪️ User activity tracking 📌 Clean, reliable way to add auditing without reinventing the wheel. #SpringBoot #Java #BackendDevelopment #SoftwareEngineering #ProgrammingTips
To view or add a comment, sign in
-
-
⚡ One thing that improved my API performance : Reducing unnecessary database calls. Sounds simple, but it made a huge difference. What I did: 🔹 Optimized queries 🔹 Used caching where needed 🔹 Avoided repeated calls in loops Small changes → big impact. #Java #BackendDevelopment #Performance #Microservices
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
-
-
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
-
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