Isolation in the context of ACID transactions ensures that each transaction’s operations are separated from other transactions until completed, preventing interference and maintaining data consistency. Isolation in ACID transactions can be achieved through various techniques, to name a few:
Locks (exclusive and shared locks)
Optimistic concurrency control
Pessimistic concurrency control
Snapshot isolation
Multiversion concurrency control
In this Answer, we focus on achieving isolation using a locking mechanism that includes exclusive and shared locks. Let’s dive in!
Isolation in concurrent transactions, facilitated by exclusive and shared locks, ensures that each transaction’s operations are independent and protected from interference. In an initial state, concurrent transactions with a pipeline of changes to be applied are executed. Exclusive locks are acquired to prevent other transactions from modifying resources until changes are committed, while shared locks allow concurrent read operations while preventing write operations from interfering.
The locks-based isolation mechanism ensures that transactions proceed as if they were the only ones operating, maintaining data consistency and integrity. Once transactions are completed, changes are applied, and the system transitions to a final state reflecting the combined effects of all transactions, with locks released accordingly to allow for continued access and modification.
Following are some real-world examples of isolation:
Flash sale: Let’s say a flash sale event is conducted by a retail company with a limited quantity of 100k units available. The system must ensure that customer orders do not exceed the available quantity. Each customer’s order submission represents a separate transaction. To maintain isolation, the system employs exclusive locks to prevent multiple customers from placing orders concurrently that could potentially exceed the available quantity. This ensures that each order is processed independently and the total quantity of units ordered does not exceed the available stock. Isolation guarantees that the integrity of the available stock is preserved throughout the flash sale event.
Flight booking: In a flight booking system, multiple users may simultaneously search for and book flights for their travel plans. Each booking transaction involves reserving seats on a flight, which represents a resource that must be managed carefully to avoid overbooking or double bookings. Isolation mechanisms, such as exclusive locks, can ensure that only one booking transaction modifies the available seat inventory at any time. This prevents scenarios where multiple users might book the same seat simultaneously or where the total number of bookings exceeds the available capacity of the flight. Isolation in the flight booking system guarantees the consistency and accuracy of seat availability throughout the booking process, regardless of concurrent user interactions.
The following code example will explain the isolation with the help of a real-world scenario:
import threadingclass FlightBookingSystem:def __init__(self, total_seats):self.total_seats = total_seatsself.available_seats = total_seatsself.lock = threading.Lock()def book_seat(self, customer_name, seats_to_book):with self.lock: # A mutual exclusion lockif self.available_seats >= seats_to_book:print(f"{customer_name} booked {seats_to_book} seat(s).")self.available_seats -= seats_to_bookelse:print(f"Sorry, {customer_name}, not enough seats available.")def book_seats(flight_booking_system, customer_name, seats_to_book):flight_booking_system.book_seat(customer_name, seats_to_book)# Creating a FlightBookingSystem instance with 100 total seatsflight_booking_system = FlightBookingSystem(total_seats=100)# Simulating multiple customers trying to book seats concurrentlycustomers = [("Customer A", 30), ("Customer B", 30), ("Customer C", 50)]threads = []for customer_name, seats_to_book in customers:thread = threading.Thread(target=book_seats, args=(flight_booking_system, customer_name, seats_to_book))threads.append(thread)thread.start()for thread in threads:thread.join()print(f"Total available seats after bookings: {flight_booking_system.available_seats}")
Note: Check out the Understand how to achieve concurrecy using threading in Python Answer to learn more.
Line 1: We import the threading module for concurrent execution of code.
Lines 3–7: We define a class named FlightBookingSystem
to manage flight bookings. The class has an init
method to initialize the total number of seats and available seats, and it also initializes a threading lock for synchronization.
Lines 9–15: We define a method named book_seat
within the FlightBookingSystem
class to book seats for customers. The method checks if there are enough available seats to book for the given customer. If available, it books the seats and updates the available seats count. It uses a threading mutual exclusion (mutex) lock self.lock
to ensure thread safety while modifying the available seats count.
Lines 17–18: We define a function named book_seats
to simulate booking seats for a customer using the FlightBookingSystem
instance.
Line 21: We create a FlightBookingSystem
instance named flight_booking_system
with a total of 100 seats.
Line 24: Simulate multiple customers trying to book seats concurrently. Each customer is represented as a tuple containing the customer's name and the number of seats they want to book. Threads are created for each customer, targeting the book_seats
function, and started for concurrent execution.
Lines 26–33: Then we ensured all threads had completed execution before proceeding.
Line 35: We print the total available seats after all bookings have been attempted.
Isolation in ACID transactions plays a crucial role in maintaining data consistency and integrity by ensuring that each transaction's operations are independent and protected from interference. Through mechanisms such as exclusive and shared locks, concurrent transactions proceed as if they were the only ones operating, safeguarding against potential conflicts.
Free Resources