Ответ 1
Блокировка таблиц не позволяет другим пользователям БД влиять на заблокированные строки/таблицы. Но блокировки сами по себе НЕ гарантируют, что ваша логика выйдет в согласованном состоянии.
Подумайте о банковской системе. Когда вы оплачиваете онлайн-счет, на транзакцию влияет не менее двух аккаунтов: ваша учетная запись, из которой берутся деньги. И учетная запись получателя, в которую перечисляются деньги. И банковский счет, в который они с радостью будут перечислять все комиссионные, взимаемые с транзакции. Учитывая (как все знают в наши дни), что банки необычайно глупы, пусть говорят, что их система работает следующим образом:
$balance = "GET BALANCE FROM your ACCOUNT";
if ($balance < $amount_being_paid) {
charge_huge_overdraft_fees();
}
$balance = $balance - $amount_being paid;
UPDATE your ACCOUNT SET BALANCE = $balance;
$balance = "GET BALANCE FROM receiver ACCOUNT"
charge_insane_transaction_fee();
$balance = $balance + $amount_being_paid
UPDATE receiver ACCOUNT SET BALANCE = $balance
Теперь, без блокировок и транзакций, эта система уязвима для различных условий гонки, самой большой из которых является несколько платежей, выполняемых в вашей учетной записи, или учетная запись получателя параллельно. В то время как ваш код имеет ваш баланс, полученный и выполняет функцию vast_overdraft_fees() и еще много чего, вполне возможно, что некоторые другие платежи будут работать с одним и тем же типом кода параллельно. Они будут получать ваш баланс (скажем, 100 долларов США), совершают свои транзакции (вынимают 20 долларов США, которые вы платите, и 30 долларов, за которые вы их заманиваете), и теперь оба пути кода имеют два разных баланса: 80 долларов США и $70. В зависимости от того, какие из них заканчиваются последним, вы получите один из двух балансов в своей учетной записи, вместо 50 долларов США, которые вы должны были получить (от $100 до $20 - $30). В этом случае "банковская ошибка в вашу пользу".
Теперь скажем, вы используете блокировки. Сначала вы получаете платеж по счету (20 долларов США), поэтому он выигрывает и блокирует вашу учетную запись. Теперь у вас есть эксклюзивное использование, и вы можете вычесть 20 долларов из баланса, и снова записать новый баланс... и ваша учетная запись заканчивается на 80 долларов, как ожидается. Но... ухо... Ты пытаешься обновить учетную запись приемника, и он заблокирован и заблокирован дольше, чем позволяет код, выбирая свою транзакцию... Мы имеем дело с глупыми банками, поэтому вместо правильной ошибки обработка кода просто тянет exit()
, а ваши 20 долларов исчезают в слое электронов. Теперь у вас 20 долларов, и вы все равно должны 20 долларов за приемник, а ваш телефон получает обратно.
Итак... введите транзакции. Вы начинаете транзакцию, вы дебетеваете свою учетную запись на 20 долларов США, вы пытаетесь кредитовать получателя с помощью 20 долларов... и что-то снова взрывается. Но на этот раз вместо exit()
код может просто сделать rollback
, а poof, ваши 20 долларов магически добавлены обратно в вашу учетную запись.
В конце концов, это сводится к следующему:
Блокировки не позволяют кому-либо другому вмешиваться в любые записи базы данных, с которыми вы имеете дело. Транзакции содержат любые "более поздние" ошибки от вмешательства в "ранние" вещи, которые вы сделали. Ни один из них не может гарантировать, что в итоге все будет хорошо. Но вместе они делают.
в завтрашнем уроке: Радость тупиков.