Introduction to concurrency control and transaction management
by K. Yue
1. Concepts of Concurrency Control
Example:
Transfer $200 from account 1234 to 2345
http://en.wikipedia.org/wiki/SQL#Transaction_controls
Task t1:
-- Assume: account 1234 = $1,000, account 2345: $500
UPDATE Account SET amount=amount-200 WHERE account_number=1234; -- (1) inconsistent state at this point.
UPDATE Account SET amount=amount+200 WHERE account_number=2345; -- (2)
Sequence #1:
(1) Task t1 step (1)
(2) Task t1 step (2)
Sequence #2: read-write anomaly
(1) Task t1 step (1)
(2) Task t2 account reports:
account 1234 = $800, account 2345: $500
(3) Task t1 step (2)
Sequence #3: System crashes and recovery
(1) Task t1 step (1)
(2) System crashes; task t1 aborted after step (1)
Sequence #4: write-write anomaly
(1) Task t1 step (1)
(2) Task t2 read account amounts, calculate interest and update accounts. Interest will be calculated based on account 1234 = $800, account 2345: $500
(3) Task t1 step (2)
ACID
START TRANSACTION;
UPDATE Account SET amount=amount-200 WHERE account_number=1234;
UPDATE Account SET amount=amount+200 WHERE account_number=2345;
IF ERRORS=0 COMMIT;
IF ERRORS<>0 ROLLBACK;
Programmer' responsibility In terms of ACID:
START TRANSACTION;
UPDATE Account SET amount=amount-200 WHERE account_number=1234;
UPDATE Account SET amount=amount+400 WHERE account_number=2345;
IF ERRORS=0 COMMIT;
IF ERRORS<>0 ROLLBACK;
2. MySQL Transaction Management
Example:
This is not a realistic example but it shows you an example of transaction management.
Suppose we have an ActiveStudent table:
create table if not exists activeStudent(
stuId varchar(6),
lastName varchar(20) NOT NULL,
firstName varchar(20) NOT NULL,
numCourses integer(4) DEFAULT 0
);
select * from activeStudent;
insert into activeStudent(stuId, lastName, firstName, numCourses)
select s.stuId, s.lastName, s.firstName, count(e.classNumber) as numCourses
from Student s natural join Enroll e
group by s.stuId, s.lastName, s.firstName;
select * from activeStudent;
When we add the enrollment ('S1010', 'HST2015A', null), we need to perform two tasks:
When we add the enrollment ('S1013', 'HST2015A', null), we need to perform two tasks:
We can write a procedure to do so:
drop procedure if exists enroll;
delimiter //
create procedure enroll
(in stuid varchar(6),
in classNumber varchar(8),
in grade varchar(2))
begin
declare already_in int default 0;
declare exit handler for sqlexception rollback;
start transaction;
insert into enroll
values (stuid, classNumber, grade);
select count(*) into already_in
from activestudent a
where a.stuid = stuid;
if (already_in > 0) then
update activestudent a
set a.numCourses = a.numCourses + 1
where a.stuid = stuid;
else
insert into activestudent
select s.stuid, s.lastName, s.firstName, count(e.classNumber)
from student s, enroll e
where s.stuid = e.stuid
and s.stuid = stuid;
end if;
commit;
end //
delimiter ;
call enroll('S1010', 'HST205A', null);
call enroll('S1013', 'HST205A', null);
-- clean up
delete from enroll
where stuid = 'S1010'
and classNumber = 'HST205A';
delete from enroll
where stuid = 'S1013'
and classNumber = 'HST205A';