Sunteți pe pagina 1din 12

Laborator: Gruparea interogărilor în tranzacții

Bine ați venit la laboratorul nostru despre gruparea interogărilor în tranzacții în MySQL. În acest
laborator, veți învăța despre conceptul de tranzacții și modul în care acestea pot fi utilizate pentru
a grupa și gestiona interogările în cadrul unei baze de date. Vom folosi baza de date "employees"
pentru a explora aceste concepte. Urmați pașii de mai jos pentru a finaliza laboratorul.

Pasul 1: Introducere în tranzacții și importanța lor

1. Citirea materialului introductiv despre tranzacții și importanța lor în gestionarea datelor


în bazele de date.
2. Reflectați asupra importanței tranzacțiilor în asigurarea consistenței datelor și evitarea
anomaliilor. Gândiți-vă la situații concrete în care tranzacțiile sunt esențiale.

Pasul 2: Utilizarea comenzilor BEGIN, COMMIT și ROLLBACK

1. În acest pas, veți învăța sintaxa și funcționalitatea comenzilor BEGIN, COMMIT și


ROLLBACK.

Exemplu:

create database accounts;

use accounts;

CREATE TABLE accounts (

name VARCHAR(30),

balance DECIMAL(10,2)

);

INSERT INTO accounts VALUES ('Paul', 1000), ('Peter', 2000);

SELECT * FROM accounts;

+-------+---------+

| name | balance |

+-------+---------+

| Paul | 1000.00 |

| Peter | 2000.00 |

+-------+---------+

Page | 1
-- Transfer banii dintr-un cont in altul

START TRANSACTION;

UPDATE accounts SET balance = balance - 100 WHERE name = 'Paul';

UPDATE accounts SET balance = balance + 100 WHERE name = 'Peter';

COMMIT; -- Commit tranzactia si inchid tranzactia

SELECT * FROM accounts;

+-------+---------+

| name | balance |

+-------+---------+

| Paul | 900.00 |

| Peter | 2100.00 |

+-------+---------+

START TRANSACTION;

UPDATE accounts SET balance = balance - 100 WHERE name = 'Paul';

UPDATE accounts SET balance = balance + 100 WHERE name = 'Peter';

ROLLBACK; -- anulez modificarile tranzactiei si inchid tranzactia

SELECT * FROM accounts;

+-------+---------+

| name | balance |

+-------+---------+

| Paul | 900.00 |

| Peter | 2100.00 |

+-------+---------+

Page | 2
Dacă deschizi un alt client MySQL și faci un SELECT în timpul tranzacției (înainte de commit
sau rollback), nu vei vedea modificările.

În mod alternativ, poți dezactiva modul numit autocommit, care este activat în mod implicit și va
face commit la fiecare instrucțiune SQL în parte.

-- Disable autocommit prin asignarea valorii false (0)

SET autocommit = 0;

UPDATE accounts SET balance = balance - 100 WHERE name = 'Paul';

UPDATE accounts SET balance = balance + 100 WHERE name = 'Peter';

COMMIT;

SELECT * FROM accounts;

+-------+---------+

| name | balance |

+-------+---------+

| Paul | 800.00 |

| Peter | 2200.00 |

+-------+---------+

UPDATE accounts SET balance = balance - 100 WHERE name = 'Paul';

UPDATE accounts SET balance = balance + 100 WHERE name = 'Peter';

ROLLBACK;

SELECT * FROM accounts;

+-------+---------+

| name | balance |

+-------+---------+

| Paul | 800.00 |

Page | 3
| Peter | 2200.00 |

+-------+---------+

SET autocommit = 1; -- Enable autocommit

Exemplu folosind baza de date sakilla:

-- session 1
SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

START TRANSACTION;
INSERT INTO sakila.actor (first_name, last_name)
VALUES ("BRUCE", "JOHNSON");
SELECT last_name INTO @last_name
FROM sakila.actor
WHERE actor_id = LAST_INSERT_ID();
UPDATE sakila.actor
SET last_name = @last_name
WHERE actor_id = 1;
COMMIT;

-- session 2
SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

+----------+------------+-----------+---------------------+

| actor_id | first_name | last_name | last_update |

+----------+------------+-----------+---------------------+

| 1 | PENELOPE | JOHNSON | 2021-04-04 15:58:56 |

Page | 4
| 201 | BRUCE | JOHNSON | 2021-04-04 15:58:56 |

| 2 | NICK | WAHLBERG | 2006-02-15 04:34:33 |

| 3 | ED | CHASE | 2006-02-15 04:34:33 |

| 4 | JENNIFER | DAVIS | 2006-02-15 04:34:33 |

+----------+------------+-----------+---------------------+

5 rows in set (0.00 sec)

In exemplul de mai sus avem deschise doua sesiuni concurente la un server MySQL. In prima sesiune
este deschisa o tranzactie care include doua instructiuni de manipulare a datelor, o adaugare a unei noi
inregistrari, respectiv o actualizarea a valorilor de la nivelul unei alte inregistrari.

Actualizarea se desfasoara cu o valoare preluata din inregistrarea nou introdusa in tabelul sakila.actor.

Pentru a anula modificarile aduse bazei de date prin intermediul tranzactiei curente, se
utilizeaza instructiunea ROLLBACK. Actualizarile realizate asupra detelor din tabele
netranzactionale nu vor putea fi anulate, iar la apelul instructiunii ROLLBACK serverul va genera
un avertisment.

SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

START TRANSACTION;
INSERT INTO sakila.actor (first_name, last_name)
VALUES ("BRUCE", "JOHNSON");
SELECT last_name INTO @last_name
FROM sakila.actor
WHERE actor_id = LAST_INSERT_ID();
UPDATE sakila.actor
SET last_name = @last_name
WHERE actor_id = 1;

Page | 5
SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;
ROLLBACK;

SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

Chiar daca la nivelul tranzactiei sunt operate doua modificari asupra datelor din tabelul
sakila.actor, datele revin la versiunea precursoare tranzactiei prin finalizarea acesteia fara
salvarea rezultatelor. Acest lucru este asigurat prin intermediul instructiunii ROLLBACK.

+----------+------------+--------------+---------------------+

| actor_id | first_name | last_name | last_update |

+----------+------------+--------------+---------------------+

| 1 | PENELOPE | GUINESS | 2006-02-15 04:34:33 |

| 2 | NICK | WAHLBERG | 2006-02-15 04:34:33 |

| 3 | ED | CHASE | 2006-02-15 04:34:33 |

| 4 | JENNIFER | DAVIS | 2006-02-15 04:34:33 |

| 5 | JOHNNY | LOLLOBRIGIDA | 2006-02-15 04:34:33 |

+----------+------------+--------------+---------------------+

5 rows in set (0.04 sec)

Page | 6
SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

SELECT @@SESSION.autocommit;
SET autocommit = 0;
SELECT @@SESSION.autocommit;

INSERT INTO sakila.actor (first_name, last_name)


VALUES ("BRUCE", "JOHNSON");
SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

connect
SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

Utilizare savepoints

SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

START TRANSACTION;
INSERT INTO sakila.actor (first_name, last_name)
VALUES ("BRUCE", "JOHNSON");
SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

SAVEPOINT beforeUpdatePenelopeGuiness;
UPDATE sakila.actor
SET last_name = "JOHNSON"
WHERE actor_id = 1;
SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

ROLLBACK TO SAVEPOINT beforeUpdatePenelopeGuiness;


COMMIT;

SELECT *
FROM sakila.actor
ORDER BY last_update DESC
LIMIT 5;

Page | 7
+----------+------------+-----------+---------------------+

| actor_id | first_name | last_name | last_update |

+----------+------------+-----------+---------------------+

| 201 | BRUCE | JOHNSON | 2021-04-06 06:14:34 |

| 1 | PENELOPE | GUINESS | 2006-02-15 04:34:33 |

| 2 | NICK | WAHLBERG | 2006-02-15 04:34:33 |

| 3 | ED | CHASE | 2006-02-15 04:34:33 |

| 4 | JENNIFER | DAVIS | 2006-02-15 04:34:33 |

+----------+------------+-----------+---------------------+

5 rows in set (0.04 sec)

Pasul 3: Exemplificarea importanței tranzacțiilor prin simulari de erori și revertări

1. Efectuați interogări care implică actualizări, ștergeri și inserții în baza de date


"employees".
2. Introduceți erori intenționat în aceste interogări pentru a crea conflicte și valori duplicate.
3. Utilizați comenzile ROLLBACK pentru a anula modificările și a reveni la starea inițială
în cazul apariției unei erori.

Exemplu:

SELECT * from salaries WHERE emp_no =10002;

DROP PROCEDURE IF EXISTS test_rollback_proc;

Page | 8
DELIMITER //

CREATE PROCEDURE test_rollback_proc()

BEGIN

DECLARE `_rollback` BOOL DEFAULT 0;

DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET `_rollback` = 1;

START TRANSACTION;

UPDATE salaries SET salary = salary * 2 WHERE emp_no =10002;

UPDATE salaries SET to_date = 32132221 WHERE emp_no =10002;

IF `_rollback` THEN

SELECT 'rolling back' AS status;

ROLLBACK;

ELSE

SELECT 'committing' AS status;

COMMIT;

END IF;

END//

DELIMITER ;

Page | 9
CALL test_rollback_proc();

SELECT * from salaries WHERE emp_no =10002;

In acest exemplu intoducem o eroare in tranzactie si facem managementul erorilor.

Pentru a captura o eroare avem nevoie de declare.

Insa declare are nevoie de begin end altfel da eroarea "Declare is not valid at this position.
expecting EOF ;"

În afara unei rutine stocate, nu poți folosi DECLARE și IF..THEN..ELSE..END IF. Aceste lucruri
trebuie realizate în limbajul de programare al aplicatiei.

Mai multe informatii: https://dev.mysql.com/doc/refman/8.0/en/declare-handler.html

SELECT * from salaries WHERE emp_no =10002;

DELIMITER $$

CREATE PROCEDURE `sp_fail4`()

BEGIN

DECLARE EXIT HANDLER FOR SQLEXCEPTION

BEGIN

ROLLBACK; -- rollback any changes made in the transaction

RESIGNAL; -- raise again the sql exception to the caller

END;

START TRANSACTION;

UPDATE salaries SET salary = salary * 2 WHERE emp_no =10002;

UPDATE salaries SET to_date = 32132221 WHERE emp_no =10002;

Page | 10
IF fail_condition_meet THEN

SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Custom error detected.',


MYSQL_ERRNO = 2000;

END IF;

SELECT * from salaries WHERE emp_no =10002;

COMMIT; -- this will not be executed

END$$

DELIMITER ;

call sp_fail4;

Un exemplu de cod simplificat:

DELIMITER $$

CREATE PROCEDURE `sp_fail5`()

BEGIN

DECLARE EXIT HANDLER FOR SQLEXCEPTION

BEGIN

ROLLBACK; -- rollback any error in the transaction

END;

START TRANSACTION;

UPDATE salaries SET salary = salary * 2 WHERE emp_no =10002;

Page | 11
UPDATE salaries SET to_date = 32132221 WHERE emp_no =10002;

COMMIT; -- this will not be executed

END$$

DELIMITER ;

call sp_fail5;

SELECT * from salaries WHERE emp_no =10002;

Page | 12

S-ar putea să vă placă și