CSEL-5109 – Advanced Database and Management System Lab Laboratory 02: Transaction-Atomicity, Isolation, Consistency, and Durability Submission Due: End of laboratory class, submit the file on Google Classroom/Google Form before the beginning of next laboratory class. Total Marks = X marks for Y weeks Marks will be given only to students who attend and participate during 2/3-hour laboratory class. Submission on Google Classroom/Google Form is mandatory as evidence of participation. Description of the laboratory exercise: Requirements: 1. Windows/MAC/Linux Operating System 2. PostgreSQL Transaction A transaction is a single logical unit of work which accesses and possibly modifies the contents of a database. Transactions access data using read and write operations. In order to maintain consistency in a database, before and after the transaction, certain properties are followed. These are called ACID properties. Atomicity By this, we mean that either the entire transaction takes place at once or doesn’t happen at all. There is no midway i.e. transactions do not occur partially. Each transaction is considered as one unit and either runs to completion or is not executed at all. It involves the following two operations. Abort: If a transaction aborts, changes made to database are not visible. Commit: If a transaction commits, changes made are visible. Atomicity is also known as the ‘All or nothing rule’. Consider the following transaction T consisting of T1 and T2: Transfer of 100 from account X to account Y. If the transaction fails after completion of T1 but before completion of T2.( say, after write(X) but before write(Y)), then amount has been deducted from X but not added to Y. This results in an inconsistent database state. Therefore, the transaction must be executed in entirety in order to ensure correctness of database state. Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU Consistency This means that integrity constraints must be maintained so that the database is consistent before and after the transaction. It refers to the correctness of a database. Referring to the example above, The total amount before and after the transaction must be maintained. Total before T occurs = 500 + 200 = 700. Total after T occurs = 400 + 300 = 700. Therefore, database is consistent. Inconsistency occurs in case T1 completes but T2 fails. As a result T is incomplete. Isolation This property ensures that multiple transactions can occur concurrently without leading to the inconsistency of database state. Transactions occur independently without interference. Changes occurring in a particular transaction will not be visible to any other transaction until that particular change in that transaction is written to memory or has been committed. This property ensures that the execution of transactions concurrently will result in a state that is equivalent to a state achieved these were executed serially in some order. Let X= 500, Y = 500. Consider two transactions T and T”. Suppose T has been executed till Read (Y) and then T’’ starts. As a result , interleaving of operations takes place due to which T’’ reads correct value of X but incorrect value of Y and sum computed by T’’: (X+Y = 50, 000+500=50, 500) is thus not consistent with the sum at end of transaction: T: (X+Y = 50, 000 + 450 = 50, 450). This results in database inconsistency, due to a loss of 50 units. Hence, transactions must take place in isolation and changes should be visible only after they have been made to the main memory. Durability: Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU This property ensures that once the transaction has completed execution, the updates and modifications to the database are stored in and written to disk and they persist even if a system failure occurs. These updates now become permanent and are stored in non-volatile memory. The effects of the transaction, thus, are never lost. The ACID properties, in totality, provide a mechanism to ensure correctness and consistency of a database in a way such that each transaction is a group of operations that acts a single unit, produces consistent results, acts in isolation from other operations and updates that it makes are durably stored. Isolation Level Isolation levels define the degree to which a transaction must be isolated from the data modifications made by any other transaction in the database system. A transaction isolation level is defined by the following phenomena Dirty Read – A Dirty read is a situation when a transaction reads data that has not yet been committed. For example, Let’s say transaction 1 updates a row and leaves it uncommitted, meanwhile, Transaction 2 reads the updated row. If transaction 1 rolls back the change, transaction 2 will have read data that is considered never to have existed. Non Repeatable read – Non Repeatable read occurs when a transaction reads the same row twice and gets a different value each time. For example, suppose transaction T1 reads data. Due to concurrency, another transaction T2 updates the same data and commit, Now if transaction T1 rereads the same data, it will retrieve a different value. Phantom Read – Phantom Read occurs when two same queries are executed, but the rows retrieved by the two, are different. For example, suppose transaction T1 retrieves a set of rows that satisfy some search criteria. Now, Transaction T2 generates some new rows that match the search criteria for transaction T1. If transaction T1 re-executes the statement that reads the rows, it gets a different set of rows this time. Based on these phenomena, The SQL standard defines four isolation levels : Read Uncommitted – Read Uncommitted is the lowest isolation level. In this level, one transaction may read not yet committed changes made by other transactions, thereby allowing dirty reads. At this level, transactions are not isolated from each other. Read Committed – This isolation level guarantees that any data read is committed at the moment it is read. Thus it does not allow dirty read. The transaction holds a read or write lock on the current row, and thus prevents other transactions from reading, updating, or deleting it. Repeatable Read – This is the most restrictive isolation level. The transaction holds read locks on all rows it references and writes locks on referenced rows for update and delete actions. Since other transactions cannot read, update or delete these rows, consequently it avoids non-repeatable read. Serializable – This is the highest isolation level. A serializable execution is guaranteed to be serializable. Serializable execution is defined to be an execution of operations in which concurrently executing transactions appears to be serially executing. Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU The Table is given below clearly depicts the relationship between isolation levels, read phenomena, and locks : Anomaly Serializable is not the same as Serializable. That is, it is necessary, but not sufficient that a Serializable schedule should be free of all three phenomena types. Practical Example: Download PostgreSQL from the following link and install the PostgreSQL on your computer. https://www.postgresql.org/ Open SQL Shell and keep pressing Enter until password is asked and provide the password that you used while installing PostgreSQL. Create a database on PostgreSQL and select your database. postgres=# CREATE DATABASE aciddb; postgres=# \c aciddb Create the following two tables Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU aciddb =# create table products (pid serial primary key, name text, price float, inventory integer); aciddb =# create table sales( saleid serial primary key, pid integer, price float, quantity integer); aciddb =# insert into products (name, price, inventory) values(‘phone’, 999.9, 100); aciddb =# select*from products; pid | name | price | inventory -----+-------+--------+----------1 | Phone | 999.99 | 100 (1 row) Atomicity Let’s begin the transaction and overserve the effect of atomicity. Do not commit the transaction. aciddb =# begin transaction; BEGIN aciddb =*# update products set inventory = inventory - 10; UPDATE 1 aciddb =*# insert into sales (pid, price, quantity) values(1,999.99, 10); INSERT 0 1 aciddb =*# select* from products; pid | name | price | inventory -----+-------+--------+----------1 | Phone | 999.99 | 90 (1 row) At this stage, close the window/terminal and open the SQL Shell again. Issue the following command and observe the outcome of the query. Did the update persist in the database? aciddb =*# select* from products; aciddb =*# select* from sales; Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU Let’s begin the transaction again and commit the transaction after updating both products and sales table. aciddb =# begin transaction; BEGIN aciddb =*# update products set inventory = inventory - 10; UPDATE 1 aciddb =*# insert into sales (pid, price, quantity) values(1,999.99, 10); INSERT 0 1 aciddb =*# select* from products; pid | name | price | inventory -----+-------+--------+----------1 | Phone | 999.99 | 90 (1 row) aciddb =*# commit; COMMIT aciddb =*# select* from products; aciddb =*# select* from sales; Did you notice the changes in both tables: products and sales? Isolation Let’s first insert several entities into sales table to show the effect of isolation. aciddb =# insert into sales (pid, price, quantity) values(1, 999.99, 5); INSERT 0 1 aciddb =# insert into sales (pid, price, quantity) values(1, 999.99, 5); INSERT 0 1 aciddb =# insert into sales (pid, price, quantity) values(2, 99.99, 10); INSERT 0 1 Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU aciddb =# insert into sales (pid, price, quantity) values(2, 89.99, 10); INSERT 0 1 aciddb =# insert into sales (pid, price, quantity) values(2, 79.99, 20); INSERT 0 1 aciddb =# select*from sales; saleid | pid | price | quantity --------+-----+--------+---------1 | 1 | 999.99 | 10 2 | 1 | 999.99 | 5 3 | 1 | 999.99 | 5 4 | 2 | 99.99 | 10 5 | 2 | 89.99 | 10 6 | 2 | 79.99 | 20 (6 rows) Now, insert a row into products table and see the effect of rollback aciddb =# insert into products(name,price, inventory) values('Earbuds', 99.9, 160); INSERT 0 1 aciddb =# select*from products; pid | name | price | inventory -----+---------+--------+----------1 | Phone | 999.99 | 2 | Earbuds | 99.9 | 90 160 (2 rows) aciddb =# select*from products; Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU pid | name | price | inventory -----+-------+--------+----------1 | Phone | 999.99 | 90 (1 row) aciddb =# select*from sales; saleid | pid | price | quantity --------+-----+--------+---------1 | 1 | 999.99 | 10 (1 row) aciddb =*# rollback; ROLLBACK Isolation Level: Repeatable Read In this example, we see how to isolate transaction using repeatable read isolation level. We will open two terminal or windows and execute the following commands to see the effect of repeatable read. Terminal/window 1 aciddb =# begin transaction isolation level repeatable read; BEGIN aciddb =*# select pid, price, quantity from sales; pid | price | quantity -----+--------+---------1 | 999.99 | 10 1 | 999.99 | 5 1 | 999.99 | 5 2 | 99.99 | 10 2 | 89.99 | 10 2 | 79.99 | 20 Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU 1 | 99.99 | 10 (7 rows) aciddb =*# select pid, count(pid) from sales group by pid; pid | count -----+------2| 3 1| 4 (2 rows) Go to Terminal 2 aciddb =*# select*from sales; saleid | pid | price | quantity --------+-----+--------+---------1 | 1 | 999.99 | 10 2 | 1 | 999.99 | 5 3 | 1 | 999.99 | 5 4 | 2 | 99.99 | 10 5 | 2 | 89.99 | 10 6 | 2 | 79.99 | 20 7 | 1 | 99.99 | 10 (7 rows) aciddb =*# select pid, count(pid) from sales group by pid; pid | count -----+------2| 3 Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU 1| 4 (2 rows) aciddb =*# commit; COMMIT aciddb =# select pid, count(pid) from sales group by pid; pid | count -----+------2| 3 1| 6 (2 rows) Terminal/window 2 aciddb =# begin transaction; BEGIN aciddb =*# insert into sales( pid, price, quantity) values(1, 99.99, 10); INSERT 0 1 aciddb =*# update products set inventory = inventory-10 where pid =1; UPDATE 1 aciddb =*# commit; COMMIT Go to Terminal 2 aciddb =# insert into sales( pid, price, quantity) values(1, 99.99, 10); INSERT 0 1 aciddb =# update products set inventory = inventory-10 where pid =1; UPDATE 1 Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU aciddb =# begin transaction; BEGIN aciddb =*# insert into sales( pid, price, quantity) values(1, 99.99, 10); INSERT 0 1 aciddb =*# update products set inventory = inventory-10 where pid =1; UPDATE 1 aciddb =*# commit; COMMIT aciddb =# Repeatable Read The following example shows you the effect of repeatable read. Terminal/window 1 aciddb =*# begin transaction isolation level repeatable read; aciddb =*# select pid, count(pid) from sales group by pid; Go to Terminal/window2 aciddb =*# select pid, price, quantity from sales; aciddb =*# select pid, count(pid) from sales group by pid; Go to Terminal 2 aciddb =*# commit; aciddb =*# select pid, count(pid) from sales group by pid; Terminal/window 2 aciddb =*# begin transaction; aciddb =*# insert into sales (pid, price, quantity) values(1,99.99,10); aciddb =*# update products set inventory = inventory-10 where pid =1; aciddb =*# commit; Go to Terminal/window 1 aciddb =*# select pid, count(pid) from sales group by pid; Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU Durability To examine the durability, we will insert a row in terminal 2 and after committing we will observe the outcome in terminal 1. Likewise, we will insert a row in terminal 1 and will not commit. After that we will observe the outcome of the insertion in terminal 2. Terminal 1 aciddb =*# Select* from products; Terminal 2 aciddb =*# Insert into products (name, price, inventory) values (‘TV’, 3000, 10); aciddb =*# Select* from products; aciddb =*# Commit; Go to Terminal 1 Phantom Reads This example shows the impact of phantom reads and solution of the phantom reads. Open two terminal and issues the following commands. Terminal 1 aciddb =*# Begin transaction; aciddb =*# Select* from sales; aciddb =*# Select pid, sum(price) from sales group by pid; Go to terminal 2 aciddb =*# Select pid, sum(price) from sales group by pid; aciddb =*# Select* from sales; Rollback; aciddb =*# Begin transaction isolation level serializable; aciddb =*# Select* from sales; Go to Terminal 2 aciddb =*# Commit; aciddb =*# Select* from sales; Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU Terminal 2 aciddb =*# insert into sales (pid, price, quantity) values(1, 79.99, 30); aciddb =*# insert into sales (pid, price, quantity) values(1, 79.99, 30); //aciddb =*# Insert into sales (pid, price, date) values (1, 15, ‘feb-7-2021’); //aciddb =*# Insert into sales (pid, price, date) values (1, 15, ‘feb-7-2021’); Go to Terminal 1 Serializable vs Repeatable Read aciddb =*# Create table test( id integer, t text); aciddb =*# Insert into test(id, t) values(12, ‘a’); aciddb =*# Insert into test(id, t) values(13, ‘a’); aciddb =*# Insert into test(id, t) values(10, ‘b’); aciddb =*# Insert into test(id, t) values(11, ‘b’); aciddb =*# select*from test; Terminal 1 aciddb =*# Begin transaction isolation level repeatable read; aciddb =*# Update test set t = ‘a’ where t = ‘b’; aciddb =*# Select*from test; aciddb =*# Commit aciddb =*# Select*from test; aciddb =*# Begin transaction isolation level serializable; aciddb =*# Update test set t = ‘a’ where t = ‘b’; aciddb =*# Select*from test; aciddb =*# Rollback; aciddb =*# Begin transaction isolation level serializable; aciddb =*# Update test set t = ‘a’ where t = ‘b’; Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU aciddb =*# Select*from test; Terminal 2 aciddb =*# Begin transaction isolation level repeatable read; aciddb =*# Update test set t = ‘b’ where t = ‘a’; aciddb =*# Begin transaction isolation level repeatable read; aciddb =*# Update test set t = ‘b’ where t = ‘a’; aciddb =*# Commit; aciddb =*# Select* from test; aciddb =*# Begin transaction isolation level serializable; aciddb =*# Update test set t = ‘b’ where t = ‘a’; aciddb =*# commit; Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU Prepared by: Md Ashraf Uddin, PhD (Australia) Associate Professor, Dept. of CSE, JnU