Part 9 – Transactions, Locking and Concurrency Control

Introduction

In enterprise applications, data correctness is more important than performance.

Consider these situations:

  • Two users update the same order.
  • Multiple payment requests arrive simultaneously.
  • Inventory quantity is updated concurrently.
  • Funds are transferred between accounts.
  • Multiple microservices update the same record.

Without proper transaction management:

❌ Lost updates

❌ Dirty reads

❌ Duplicate records

❌ Inconsistent data

❌ Deadlocks

❌ Data corruption

This article covers:

✅ ACID properties

✅ Spring transactions

✅ Transaction boundaries

✅ Isolation levels

✅ Propagation

✅ Optimistic locking

✅ Pessimistic locking

✅ Deadlocks

✅ Concurrency best practices


What is a Transaction?

A transaction is a group of operations that execute as a single unit.

Example:

Transfer ₹1000

Account A  -1000
Account B  +1000

Both operations must succeed.


ACID Properties

PropertyMeaning
AtomicityAll or nothing
ConsistencyValid state
IsolationIndependent execution
DurabilityPermanent storage

Atomicity

Debit Account A

Credit Account B

If the second operation fails:

Rollback both.

Consistency

Before:

Total Balance = ₹50,000

After:

Total Balance = ₹50,000

Rules remain valid.


Isolation

Users should not interfere with each other.


Durability

After commit:

Data survives:

- Server restart
- Application crash
- Database restart

Spring Transaction Management

@Service
public class PaymentService {

    @Transactional
    public void transfer() {

    }
}

Spring:

  • Starts transaction.
  • Commits on success.
  • Rolls back on failure.

Transaction Lifecycle

Method starts
      ↓
Begin transaction
      ↓
Execute SQL
      ↓
Commit

Failure:

Exception
      ↓
Rollback

Example

@Transactional
public void transferMoney() {

    debit();

    credit();
}

Rollback Rules

By default:

RuntimeException → Rollback

Checked Exception → No rollback

Example

@Transactional(
    rollbackFor = Exception.class)

Now:

  • Checked exceptions rollback.

Transaction Boundaries

Good:

@Service
@Transactional
public void processOrder() {
}

Avoid:

@Repository
@Transactional

Business transactions belong to services.


Isolation Levels

LevelDirty ReadNon-repeatablePhantom
Read UncommittedYesYesYes
Read CommittedNoYesYes
Repeatable ReadNoNoYes
SerializableNoNoNo

Read Uncommitted

Transaction A:

Update salary = 10000

Not committed.

Transaction B reads:

10000

A rolls back.

Dirty read.

Oracle does not support this.


Read Committed

Oracle default.

Only committed data is visible.

Recommended for most applications.


Repeatable Read

Same row always returns same value.

Useful for reporting.


Serializable

Highest consistency.

Lowest concurrency.


Spring Example

@Transactional(
    isolation =
    Isolation.READ_COMMITTED)

Propagation

Defines transaction behavior.


REQUIRED

Default.

@Transactional

Join existing transaction.

Create if absent.


REQUIRES_NEW

@Transactional(
    propagation =
    Propagation.REQUIRES_NEW)

Always creates a new transaction.


Example

Order Service
      ↓
Audit Service

Audit should commit independently.


SUPPORTS

Participates if transaction exists.


NOT_SUPPORTED

Suspends transaction.

Useful for reporting.


MANDATORY

Requires existing transaction.

Throws exception otherwise.


Propagation Summary

TypeDescription
REQUIREDDefault
REQUIRES_NEWNew transaction
SUPPORTSOptional
NOT_SUPPORTEDNo transaction
MANDATORYMust exist

Optimistic Locking

Assumes conflicts are rare.

Add:

@Version
private Integer version;

Example

User A:

Version = 1

User B:

Version = 1

User A updates:

Version = 2

User B updates:

OptimisticLockException

Database

VERSION NUMBER

Update:

UPDATE EMPLOYEE
SET NAME=?,
    VERSION=2
WHERE ID=1
AND VERSION=1

Advantages

✅ High scalability

✅ No locks

✅ Better throughput


Pessimistic Locking

Assumes conflicts are frequent.


Example

@Lock(
    LockModeType.PESSIMISTIC_WRITE)

Generated SQL:

SELECT *
FROM EMPLOYEE
WHERE EMP_ID=1
FOR UPDATE

Other users wait.


Lock Types

LockPurpose
PESSIMISTIC_READRead lock
PESSIMISTIC_WRITEUpdate lock
PESSIMISTIC_FORCE_INCREMENTLock + version

When to Use Optimistic Locking

  • Web applications
  • Microservices
  • APIs
  • Low conflict systems

When to Use Pessimistic Locking

  • Inventory
  • Financial systems
  • Seat booking
  • Stock trading

Deadlocks

Example:

Transaction A:

Locks Account A
Needs Account B

Transaction B:

Locks Account B
Needs Account A

Result:

Deadlock

Oracle Deadlock Error

ORA-00060:
deadlock detected

Oracle kills one transaction.


Deadlock Prevention

Access rows consistently.

Good:

Account A
Account B

Always same order.


Keep transactions short.


Avoid user interaction inside transactions.

Bad:

Begin transaction

Display popup

Wait 30 seconds

Lost Update Problem

User A:

Salary = 10000

User B:

Salary = 10000

A saves:

12000

B saves:

11000

A’s changes lost.

Optimistic locking prevents this.


Read Only Transactions

@Transactional(
    readOnly = true)

Benefits:

  • Optimization.
  • Prevents updates.

Transaction Timeout

@Transactional(
    timeout = 30)

Rollback after 30 seconds.


Nested Transactions

Spring does not fully support true nested transactions.

Use:

REQUIRES_NEW

Example Service

@Service
public class OrderService {

    @Transactional
    public void placeOrder() {

        saveOrder();

        savePayment();

        saveShipment();
    }
}

Everything commits together.


Event Publishing

Bad:

@Transactional
public void save() {

    publishEvent();

    insert();
}

Event may publish before rollback.


Good:

@TransactionalEventListener

After commit.


Distributed Transactions

Multiple systems:

  • Payment
  • Inventory
  • Shipping

Avoid:

2PC

Prefer:

  • Saga pattern
  • Event-driven architecture

Monitoring Transactions

Look for:

  • Long transactions
  • Deadlocks
  • Blocking sessions
  • Rollbacks

Oracle views:

V$TRANSACTION

V$LOCK

V$SESSION

Common Mistakes

Transaction on Controller

Bad.


Large Transactions

Bad.


Missing Version Column

Bad.


Long Running Transactions

Bad.


Pessimistic Everywhere

Bad.


Recommended Strategy

ScenarioRecommendation
CRUD applicationOptimistic
InventoryPessimistic
BankingPessimistic
APIsOptimistic
ReportingRead-only

Interview Questions

Difference between optimistic and pessimistic locking?

Optimistic assumes low conflicts.

Pessimistic locks rows.


What is Oracle default isolation?

READ_COMMITTED.


What causes deadlocks?

Circular waiting.


Why use @Version?

Prevent lost updates.


What is propagation?

Transaction behavior between methods.


Why use readOnly?

Performance optimization.


Best Practices

✅ Put transactions in services.

✅ Keep transactions short.

✅ Use optimistic locking.

✅ Add version columns.

✅ Use read-only transactions.

✅ Avoid user interaction.

✅ Monitor deadlocks.

✅ Use timeouts.


Summary

This article covered:

✅ ACID

✅ Spring transactions

✅ Isolation levels

✅ Propagation

✅ Optimistic locking

✅ Pessimistic locking

✅ Deadlocks

✅ Lost updates

✅ Transaction monitoring


Next Article

Part 10 – Production Best Practices, Performance and Enterprise Architecture

Topics:

  • Schema standards
  • Audit columns
  • Soft deletes
  • Connection pool tuning
  • Index strategies
  • Pagination
  • Flyway and Liquibase
  • Monitoring
  • Logging
  • Production troubleshooting
  • Enterprise architecture

Leave a Reply

Your email address will not be published. Required fields are marked *