ACID
In the bustling digital world, where every click and transaction matters, how do we ensure our data remains flawless, even when systems crash or multiple users try to access it simultaneously? This is where ACID properties come into play, a set of fundamental principles that guarantee the reliability of database transactions. Understanding ACID is crucial to building robust and trustworthy systems, from your bank account to your favorite online store. ACID stands for Atomicity, Consistency, Isolation, and Durability—four interconnected principles ensuring data integrity in databases. Each ACID property addresses a unique challenge in transaction processing, from ensuring operations complete entirely to handling simultaneous user interactions. While critical for reliability, ACID principles can sometimes be relaxed in favor of other system priorities, leading to different database architectural choices.
AI Summary
In the bustling digital world, where every click and transaction matters, how do we ensure our data remains flawless, even when systems crash or multiple users try to access it simultaneously? This is where ACID properties come into play, a set of fundamental principles that guarantee the reliability of database transactions. Understanding ACID is crucial to building robust and trustworthy systems, from your bank account to your favorite online store.
- ACID stands for Atomicity, Consistency, Isolation, and Durability—four interconnected principles ensuring data integrity in databases.
- Each ACID property addresses a unique challenge in transaction processing, from ensuring operations complete entirely to handling simultaneous user interactions.
- While critical for reliability, ACID principles can sometimes be relaxed in favor of other system priorities, leading to different database architectural choices.
What is ACID?
Imagine transferring money between bank accounts. It's not just one step; it involves debiting one account and crediting another. If something goes wrong in the middle, you wouldn't want the money to vanish into thin air, would you? This is precisely the kind of problem ACID properties are designed to prevent.
In computer science, ACID is an acronym representing Atomicity, Consistency, Isolation, and Durability. These are the four pillars that guarantee data validity and reliability in database transactions, protecting against errors, power failures, and other mishaps that could otherwise corrupt information.
A 'transaction' in a database is a sequence of operations that is treated as a single, indivisible logical unit. The entire sequence must either complete successfully or fail completely. This all-or-nothing approach is the bedrock of data integrity.
The Birth of a Concept
While database transactions have been around for decades, the specific ACID acronym was coined in 1983 by Andreas Reuter and Theo Härder. They built upon earlier foundational work by computer scientist Jim Gray, who had already identified atomicity, consistency, and durability as key elements.
In fact, systems like IBM's Information Management System were already supporting ACID-like transactions as early as 1973, long before the catchy acronym made these properties a household name in the database world. This paradigm has profoundly influenced database system development ever since.
ACID vs. BASE
Just as in chemistry, where acids and bases are opposites, in databases, ACID has a counterpart: BASE. BASE stands for 'Basically Available, Soft state, Eventually consistent.' This acronym highlights a different philosophy for managing data, particularly in large-scale, distributed systems.
ACID databases prioritize consistency over availability. If any step in a transaction fails, the entire transaction is rolled back, guaranteeing perfect data. BASE databases, however, prioritize availability over strict consistency, allowing users to temporarily access data that might be slightly out of sync, with consistency eventually achieved.
The Four Pillars of ACID
Atomicity: All or Nothing
Atomicity guarantees that every transaction is treated as a single, indivisible 'unit.' Either all operations within it succeed, or none of them do. If even one part fails, the entire transaction is aborted, and the database reverts to its state before the transaction began.
Think of our bank transfer example: if the debit happens but the credit fails, atomicity ensures the debit is undone. This prevents partial updates that could leave your data in a chaotic, inconsistent state. From the outside, a transaction either hasn't happened yet, or it's completely done.
Consistency: Valid States Only
Consistency ensures that a transaction can only transition the database from one valid state to another. This means any data written must adhere to all predefined rules—like constraints, triggers, and relationships between tables.
For instance, if you have a rule that a certain column must always contain a positive number, consistency ensures no transaction can introduce a negative value. It's about preventing database corruption by illegal or illogical operations, maintaining the integrity invariants of your data.
Isolation: Working Independently
In a busy system, multiple transactions often run simultaneously, accessing and modifying the same data. Isolation ensures that these concurrent transactions don't interfere with each other, making it seem as if they're executing one after another.
Without isolation, one transaction might read incomplete changes from another, leading to incorrect results or unexpected behavior. It's like having multiple people edit a document: isolation guarantees they don't overwrite each other's work or see half-finished sentences.
Durability: Changes are Permanent
Durability guarantees that once a transaction has been successfully 'committed'—meaning it's completed all its operations and passed all checks—its effects will persist, even if the system subsequently crashes or loses power.
This usually involves writing the transaction's changes to non-volatile storage, like a hard drive, before confirming success to the user. So, when your banking app says 'transaction successful,' durability ensures that success is truly permanent.
ACID in Action: Examples
Let's illustrate these properties with a simple database table containing two columns, A and B. We'll enforce one crucial rule: the sum of the values in A and B must always equal 100.
Atomicity Example: The Money Transfer
Consider our bank transfer again: take $10 from Account A, add $10 to Account B. These are two distinct steps. Atomicity ensures that if the 'add to B' step fails, the 'take from A' step is automatically undone. You wouldn't want to see your money disappear, would you?
The transaction is a single, unbreakable unit. If the system crashes after debiting A but before crediting B, atomicity dictates that Account A will be restored to its original balance. No partial updates, no lost funds.
Consistency Example: Upholding the Rule
Suppose our table has A=50 and B=50, satisfying A+B=100. A transaction attempts to subtract 10 from A, making A=40, but doesn't touch B. If this operation were allowed to complete, A+B would become 90—violating our fundamental rule.
Consistency steps in! It recognizes that the resulting state (A=40, B=50) is invalid. The entire transaction is canceled, and the database rolls back to its pre-transaction state of A=50, B=50. The rule A+B=100 remains unbroken.
Isolation Example: Preventing Interference
Imagine two separate transactions, T1 and T2, trying to modify the same data at the same time. T1 wants to update A, and T2 also wants to update A. Without isolation, they could easily overwrite each other's changes, leading to an incorrect final value.
Isolation ensures that T2 won't start its update on A until T1 has fully completed its operation and either committed or rolled back. This serial execution—even if happening concurrently under the hood—guarantees that T2 sees a consistent state of A, not a partially updated one.
Durability Example: Surviving a Crash
Let's say a transaction successfully transfers $10 from A to B. The system tells the user, 'Done!' But what if these changes are still only sitting in a temporary memory buffer, waiting to be written permanently to the hard drive?
If a power outage occurs right after the 'success' message but before the changes hit permanent storage, the user's perception of a completed transaction is shattered. Durability demands that once committed, these changes are immediately and permanently recorded, surviving any subsequent system failure.
How ACID is Achieved
Ensuring ACID properties isn't simple. It requires sophisticated mechanisms to handle potential failures and concurrent access. Two primary techniques stand out: write-ahead logging and shadow paging.
Locking vs. Multiversioning
Many traditional databases rely on 'locking' to enforce isolation. When a transaction accesses data, it 'locks' it, preventing other transactions from modifying it until the first one is complete. This ensures consistency but can slow things down, as other transactions must wait.
An alternative, 'multiversion concurrency control' (MVCC), takes a different approach. When a transaction modifies data, the database creates a new version. Readers are given the older, consistent version, while writers work on the new one. This allows readers and writers to operate simultaneously, significantly improving performance in many scenarios.
Distributed Transactions
Implementing ACID properties becomes even more complex when transactions span across multiple databases or different physical machines—what we call 'distributed transactions.' What if one part of the transaction succeeds, but another fails due to a network issue?
For this, protocols like the 'two-phase commit' are used. A coordinator node first asks all participating nodes if they are 'prepared' to commit their part of the transaction. Only if all nodes confirm readiness does the coordinator issue a final 'commit' command, ensuring atomicity across the entire distributed system.
Article
ACID
In computer science, ACID (atomicity, consistency, isolation, durability) is a set of properties of database transactions intended to guarantee data validity despite errors, power failures, and other mishaps. For example, a transfer of funds from one bank account to another, involving multiple changes such as debiting one account and crediting another, is a single transaction.
In 1983, Andreas Reuter and Theo Härder coined the acronym ACID, building on earlier work by Jim Gray who named atomicity, consistency, and durability, but not isolation, when characterizing the transaction concept. These four properties are the major guarantees of the transaction paradigm, which has influenced many aspects of development in database systems.
According to Gray and Reuter, the IBM Information Management System supported ACID transactions as early as 1973 (although the acronym was created later).
BASE stands for basically available, soft state, and eventually consistent: the acronym highlights that BASE is opposite of ACID, like their chemical equivalents. ACID databases prioritize consistency over availability — the whole transaction fails if an error occurs in any step within the transaction; in contrast, BASE databases prioritize availability over consistency: instead of failing the transaction, users can access inconsistent data temporarily: data consistency is achieved, but not immediately. A database either leans towards ACID or BASE, but it cannot be both (according to CAP theorem). For example, SQL databases (like MySQL, PostgreSQL, AWS RedShift) are structured over the ACID model, while NoSQL databases (like DynamoDB or MongoDB) use the BASE architecture. However, some NoSQL databases might exhibit certain ACID traits.
Characteristics
ACID
The characteristics of these four properties as defined by Reuter and Härder are as follows:
Atomicity
Transactions are often composed of multiple statements. Atomicity guarantees that each transaction is treated as a single "unit", which either succeeds completely or fails completely: if any of the statements constituting a transaction fails to complete, the entire transaction fails and the database is left unchanged. An atomic system must guarantee atomicity in each and every situation, including power failures, errors, and crashes. A guarantee of atomicity prevents updates to the database from occurring only partially, which can cause greater problems than rejecting the whole series outright. As a consequence, the transaction cannot be observed to be in progress by another database client. At one moment in time, it has not yet happened, and at the next, it has already occurred in whole (or nothing happened if the transaction was cancelled in progress).
Consistency
Consistency ensures that a transaction can only bring the database from one consistent state to another, preserving database invariants: any data written to the database must be valid according to all defined rules, including constraints, cascades, triggers, and any combination thereof. This prevents database corruption by an illegal transaction. An example of a database invariant is referential integrity, which guarantees the primary key–foreign key relationship.
Isolation
Transactions are often executed concurrently (e.g., multiple transactions reading and writing to a table at the same time). Isolation ensures that concurrent execution of transactions leaves the database in the same state that would have been obtained if the transactions were executed sequentially. Isolation is the main goal of concurrency control; depending on the isolation level used, the effects of an incomplete transaction might not be visible to other transactions.
Durability
Durability guarantees that once a transaction has been committed, it will remain committed even in the case of a system failure (e.g., power outage or crash). This usually means that completed transactions (or their effects) are recorded in non-volatile memory.
Examples
ACID
The following examples further illustrate the ACID properties. In these examples, the database table has two columns, A and B. An integrity constraint requires that the value in A and the value in B must sum to 100. The following SQL code creates a table as described above:
Atomicity
Atomicity is the guarantee that series of database operations in an atomic transaction will either all occur (a successful operation), or none will occur (an unsuccessful operation). The series of operations cannot be separated with only some of them being executed, which makes the series of operations "indivisible". A guarantee of atomicity prevents updates to the database from occurring only partially, which can cause greater problems than rejecting the whole series outright. In other words, atomicity means indivisibility and irreducibility. Alternatively, we may say that a logical transaction may be composed of several physical transactions. Unless and until all component physical transactions are executed, the logical transaction will not have occurred.
An example of an atomic transaction is a monetary transfer from bank account A to account B. It consists of two operations, withdrawing the money from account A and depositing it to account B. We would not want to see the amount removed from account A before we are sure it has also been transferred into account B. Performing these operations in an atomic transaction ensures that the database remains in a consistent state, that is, money is neither debited nor credited if either of those two operations fails.
Consistency failure
Consistency is a very general term, which demands that the data must meet all validation rules. In the previous example, the validation is a requirement that A + B = 100. All validation rules must be checked to ensure consistency. Assume that a transaction attempts to subtract 10 from A without altering B. Because consistency is checked after each transaction, it is known that A + B = 100 before the transaction begins. If the transaction removes 10 from A successfully, atomicity will be achieved. However, a validation check will show that A + B = 90, which is inconsistent with the rules of the database. The entire transaction must be canceled and the affected rows rolled back to their pre-transaction state. If there had been other constraints, triggers, or cascades, every single change operation would have been checked in the same way as above before the transaction was committed. Similar issues may arise with other constraints. We may have required the data types of both A and B to be integers. If we were then to enter, say, the value 13.5 for A, the transaction will be canceled, or the system may give rise to an alert in the form of a trigger (if/when the trigger has been written to this effect). Another example would be integrity constraints, which would not allow us to delete a row in one table whose primary key is referred to by at least one foreign key in other tables.
Isolation failure
To demonstrate isolation, we assume two transactions execute at the same time, each attempting to modify the same data. One of the two must wait until the other completes in order to maintain isolation.
• T1 transfers 10 from A to B. • T2 transfers 20 from B to A.
• T1 subtracts 10 from A. • T1 adds 10 to B. • T2 subtracts 20 from B. • T2 adds 20 to A.
If these operations are performed in order, isolation is maintained, although T2 must wait. Consider what happens if T1 fails halfway through. The database eliminates T1's effects, and T2 sees only valid data.
By interleaving the transactions, the actual order of actions might be:
• T1 subtracts 10 from A. • T2 subtracts 20 from B. • T2 adds 20 to A. • T1 adds 10 to B.
Again, consider what happens if T1 fails while modifying B in Step 4. By the time T1 fails, T2 has already modified A; it cannot be restored to the value it had before T1 without leaving an invalid database. This is known as a write-write contention, because two transactions attempted to write to the same data field. In a typical system, the problem would be resolved by reverting to the last known good state, canceling the failed transaction T1, and restarting the interrupted transaction T2 from the good state.
Durability failure
Consider a transaction that transfers 10 from A to B. First, it removes 10 from A, then it adds 10 to B. At this point, the user is told the transaction was a success. However, the changes are still queued in the disk buffer waiting to be committed to disk. Power fails and the changes are lost, but the user assumes (understandably) that the changes persist.
Implementation
ACID
Processing a transaction often requires a sequence of operations that is subject to failure for a number of reasons. For instance, the system may have no room left on its disk drives, or it may have used up its allocated CPU time. There are two popular families of techniques: write-ahead logging and shadow paging. In both cases, locks must be acquired on all information to be updated, and depending on the level of isolation, possibly on all data that may be read as well. In write ahead logging, durability is guaranteed by writing the prospective change to a persistent log before changing the database. That allows the database to return to a consistent state in the event of a crash. In shadowing, updates are applied to a partial copy of the database, and the new copy is activated when the transaction commits.
Locking vs. multiversioning
Many databases rely upon locking to provide ACID capabilities. Locking means that the transaction marks the data that it accesses so that the DBMS knows not to allow other transactions to modify it until the first transaction succeeds or fails. The lock must always be acquired before processing data, including data that is read but not modified. Non-trivial transactions typically require a large number of locks, resulting in substantial overhead as well as blocking other transactions. For example, if user A is running a transaction that has to read a row of data that user B wants to modify, user B must wait until user A's transaction completes. Two-phase locking is often applied to guarantee full isolation.
An alternative to locking is multiversion concurrency control, in which the database provides each reading transaction the prior, unmodified version of data that is being modified by another active transaction. This allows readers to operate without acquiring locks, i.e., writing transactions do not block reading transactions, and readers do not block writers. Going back to the example, when user A's transaction requests data that user B is modifying, the database provides A with the version of that data that existed when user B started his transaction. User A gets a consistent view of the database even if other users are changing data. One implementation, namely snapshot isolation, relaxes the isolation property.
Distributed transactions
Guaranteeing ACID properties in a distributed transaction across a distributed database, where no single node is responsible for all data affecting a transaction, presents additional complications. Network connections might fail, or one node might successfully complete its part of the transaction and then be required to roll back its changes because of a failure on another node. The two-phase commit protocol (not to be confused with two-phase locking) provides atomicity for distributed transactions to ensure that each participant in the transaction agrees on whether the transaction should be committed or not. Briefly, in the first phase, one node (the coordinator) interrogates the other nodes (the participants), and only when all reply that they are prepared does the coordinator, in the second phase, formalize the transaction.