Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding pdo mysql transactions

The PHP Documentation says:

If you've never encountered transactions before, they offer 4 major features: Atomicity, Consistency, Isolation and Durability (ACID). In layman's terms, any work carried out in a transaction, even if it is carried out in stages, is guaranteed to be applied to the database safely, and without interference from other connections, when it is committed.

QUESTION:

Does this mean that I can have two separate php scripts running transactions simultaneously without them interfering with one another?


ELABORATING ON WHAT I MEAN BY "INTERFERING":

Imagine we have the following employees table:

 __________________________
|  id  |  name  |  salary  |
|------+--------+----------|
|  1   |  ana   |   10000  |
|------+--------+----------|

If I have two scripts with similar/same code and they run at the exact same time:

script1.php and script2.php (both have the same code):

$conn->beginTransaction();

$stmt = $conn->prepare("SELECT * FROM employees WHERE name = ?");
$stmt->execute(['ana']);
$row = $stmt->fetch(PDO::FETCH_ASSOC);

$salary = $row['salary'];
$salary = $salary + 1000;//increasing salary

$stmt = $conn->prepare("UPDATE employees SET salary = {$salary} WHERE name = ?");
$stmt->execute(['ana']);

$conn->commit(); 

and assuming the sequence of events is as follows:

  • script1.php selects data

  • script2.php selects data

  • script1.php updates data

  • script2.php updates data

  • script1.php commit() happens

  • script2.php commit() happens

What would the resulting salary of ana be in this case?

  • Would it be 11000? And would this then mean that 1 transaction will overlap the other because the information was obtained before either commit happened?

  • Would it be 12000? And would this then mean that regardless of the order in which data was updated and selected, the commit() function forced these to happen individually?

Please feel free to elaborate as much as you want on how transactions and separate scripts can interfere (or don't interfere) with one another.

like image 394
Webeng Avatar asked May 31 '16 23:05

Webeng


People also ask

What is a transaction in PDO?

Introduction to PHP PDO transaction It means that the changes made to the database via the PDO object won't take effect until you call the PDO::commit() method. To commit a transaction, you call the PDO::commit() method: $pdo->commit(); Code language: PHP (php)

How do transactions work in MySQL?

In MySQL, transactions begin with the statement BEGIN WORK and end with either a COMMIT or a ROLLBACK statement. The SQL commands between the beginning and ending statements form the bulk of the transaction.

What is PDO in MySQL?

PDO_MYSQL is a driver that implements the PHP Data Objects (PDO) interface to enable access from PHP to MySQL databases. PDO_MYSQL uses emulated prepares by default.

How does PDO prepared statements work?

In layman's terms, PDO prepared statements work like this: Prepare an SQL query with empty values as placeholders with either a question mark or a variable name with a colon preceding it for each value. Bind values or variables to the placeholders. Execute query simultaneously.


2 Answers

You are not going to find the answer in php documentation because this has nothing to do with php or pdo.

Innodb table engine in mysql offers 4 so-called isolation levels in line with the sql standard. The isolation levels in conjunction with blocking / non-blocking reads will determine the result of the above example. You need to understand the implications of the various isolation levels and choose the appropriate one for your needs.

To sum up: if you use serialisable isolation level with autocommit turned off, then the result will be 12000. In all other isolation levels and serialisable with autocommit enabled the result will be 11000. If you start using locking reads, then the result could be 12000 under all isolation levels.

like image 130
Shadow Avatar answered Nov 09 '22 07:11

Shadow


Judging by the given conditions (a solitary DML statement), you don't need a transaction here, but a table lock. It's a very common confusion.

You need a transaction if you need to make sure that ALL your DML statements were performed correctly or weren't performed at all.

Means

  • you don't need a transaction for any number of SELECT queries
  • you don't need a transaction if only one DML statement is performed

Although, as it was noted in the excellent answer from Shadow, you may use a transaction here with appropriate isolation level, it would be rather confusing. What you need here is table locking. InnoDB engine lets you lock particular rows instead of locking the entire table and thus should be preferred.

In case you want the salary to be 1200 - then use table locks.

Or - a simpler way - just run an atomic update query:

UPDATE employees SET salary = salary + 1000 WHERE name = ?

In this case all salaries will be recorded.

If your goal is different, better express it explicitly.

But again: you have to understand that transactions in general has nothing to do with separate scripts execution. Regarding your topic of race condition you are interested not in transactions but in table/row locking. This is a very common confusion, and you better learn it straight:

  • a transaction is to ensure that a set of DML queries within one script were executed successfully.
  • table/row locking is to ensure that other script executions won't interfere.

The only topic where transactions and locking interfere is a deadlock, but again - it's only in case when a transaction is using locking.

like image 21
Your Common Sense Avatar answered Nov 09 '22 06:11

Your Common Sense