Transactions and Locking Demystified: Optimistic vs. Pessimistic Locking for Smooth Database Updates

2024-04-06

Locking: Imagine a database record as a file. Locking means temporarily restricting access to that file while someone is working on it. This prevents others from modifying the same data at the same time, which could lead to inconsistencies.

Transactions: A transaction is a series of database operations that are treated as a single unit. Either all the operations succeed, or none of them do. This ensures data integrity.

Optimistic Locking:

  • Idea: Be optimistic and assume multiple users won't edit the same data simultaneously.
  • Process:
    1. User reads a record's data, along with a version number (e.g., timestamp).
    2. User edits the data.
    3. User tries to save the changes.
  • Benefits:
    • No waiting for locks.
  • Drawbacks:
  • Idea: Be pessimistic and assume conflicts might happen. Acquire exclusive access to the data upfront to prevent conflicts.
  • Process:
    1. User tries to edit a record.
    2. Database locks the record, preventing others from accessing it.
    3. User saves the changes, and the lock is released.
  • Benefits:
  • Drawbacks:
    • Can lead to deadlocks (situations where two users are waiting for each other's locks to be released).

Choosing the right approach:

  • Use optimistic locking for scenarios with low contention (edits are infrequent) and good user experience is crucial (faster updates).
  • Use pessimistic locking for scenarios with high contention (frequent edits) or data consistency is paramount (financial transactions).



Optimistic Locking (Python with SQLAlchemy):

from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# Database setup
engine = create_engine('sqlite:///data.db')
Base = declarative_base()

class Product(Base):
  __tablename__ = 'products'
  id = Column(Integer, primary_key=True)
  name = Column(String)
  price = Column(Integer)
  version = Column(DateTime, nullable=False)

# Session 
Session = sessionmaker(bind=engine)
session = Session()

# Fetch product for update (with version number)
product = session.query(Product).filter_by(id=1).first()

# Modify product data
product.price = product.price + 10

# Try to update (with version check)
try:
  session.add(product)
  session.commit()
  print("Product updated successfully!")
except:
  print("Update failed - Another user might have modified the product.")
  session.rollback()

session.close()

This example uses a version column with a timestamp to track data changes. During update, it checks if the version in the database matches the one fetched earlier. If they differ, an update conflict is assumed.

Pessimistic Locking (Java with JPA):

import javax.persistence.*;

@Entity
public class Product {
  @Id
  private int id;
  private String name;
  private double price;

  // Additional getters and setters

  @Version
  private Long version;
}

// ... (rest of your code)

EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU");
EntityManager em = emf.createEntityManager();

try {
  // Begin transaction with locking
  em.getTransaction().begin();
  Product product = em.find(Product.class, 1, LockModeType.PESSIMISTIC_WRITE);

  // Modify product data
  product.setPrice(product.getPrice() * 0.9);

  // Update with guaranteed consistency (due to lock)
  em.merge(product);
  em.getTransaction().commit();
  System.out.println("Product updated successfully!");
} catch (Exception e) {
  e.printStackTrace();
  em.getTransaction().rollback();
} finally {
  em.close();
  emf.close();
}

Here, @Version annotation is used for optimistic locking (similar to the previous example). But, we explicitly acquire a pessimistic lock using LockModeType.PESSIMISTIC_WRITE during the transaction. This ensures exclusive access to the data until the transaction commits.

Remember, these are simplified examples. The specific implementation will vary depending on your programming language and database system.




Choosing the best alternative depends on your specific use case, data access patterns, and desired balance between performance and data consistency. Consider factors like:

  • Frequency of edits: If edits are infrequent, optimistic locking might suffice. For high contention scenarios, pessimistic locking or alternatives like timestamps might be better.
  • Data consistency requirements: If absolute consistency is crucial (e.g., financial transactions), pessimistic locking or serializable isolation is preferred.
  • Performance needs: For low-latency updates, optimistic locking or timestamp-based approaches might be faster than pessimistic locking.

Remember, there's no one-size-fits-all solution. Evaluate your needs and explore the available options to find the most suitable approach for your database concurrency control.


database transactions locking


C# Fun with Rainbows: Unveiling the Colorful Secrets!

Imagine sunlight is like a box of crayons with all different colors. Normally, we see the sunlight as white, like all the crayons are mixed together in a big white crayon...


Find Duplicate Rows in a MySQL Column: Two Effective Methods

Understanding the Task:SQL (Structured Query Language): It's a standardized language used to interact with relational databases like MySQL...


Understanding Maximum Records in MySQL Tables: Limits, Factors, and Best Practices

I'd be glad to explain the maximum number of records in a MySQL database table in relation to MySQL, database, and limit:...


MySQL 101: Avoiding "Error 1046" and Working with Databases Effectively

Understanding the Error:This error arises when you're working with MySQL and attempt to execute a query that interacts with tables or data...


database transactions locking