Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Denkong/7b45f70188e8ed4483ca8e22fe569f2f to your computer and use it in GitHub Desktop.
Save Denkong/7b45f70188e8ed4483ca8e22fe569f2f to your computer and use it in GitHub Desktop.
SQL - блокировки, транзакции
===SQL====
Транзакция — это операция, состоящая из одного или нескольких запросов к базе данных.
Суть транзакций — обеспечить корректное выполнение всех запросов в рамках одной транзакции,
а так-же обеспечить механизм изоляции транзакций друг от друга для решения проблемы совместного доступа к данным.
set autocommit=0; //отключаем autocommit
Start transaction; (также, можно написать BEGIN; )
Select * from table where ... FOR UPDATE; // блокирует записаь, снимается после commit
…какие-то действий с БД (insert, update,delete…)
commit; //Фиксация действий, запись их в физическую БД
====LARAVEL===
В конструкторе запросов есть несколько функций, которые помогают делать «пессимистическую блокировку» (pessimistic locking)
для ваших операторов SELECT. Для запуска оператора SELECT с «разделяемой блокировкой» вы можете использовать в запросе метод sharedLock().
Разделяемая блокировка предотвращает изменение выбранных строк до конца транзакции:
DB::table('users')->where('votes', '>', 100)->sharedLock()->get();
Или вы можете использовать метод lockForUpdate().
Блокировка «для изменения» предотвращает изменение строк и их выбор другими разделяемыми блокировками:
DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get();
===ПРИМЕР LARAVEL ====
DB::transaction(function () {
$balance = DB::table('test')->where('id', '=', 2)->lockForUpdate()->value('number');
sleep(20);
$test = DB::table('test')->where([['id',1],])->update(['number'=>$balance-10000]);
});
===ПРИМЕР С МЕТКОЙ В БД====
$balance = DB::table('test')->where('id',1)->value('number');
$edit = DB::table('test')->where('id',1)->value('edit');
if ($edit != 1){
DB::table('test')->where('id',1)->update(['edit'=>1]);
$data=[
'name'=>$req->name,
'number'=>$balance-$req->number
];
try {
$test = DB::table('test')->where([['id',1],['number',$balance]])->lockForUpdate()->update($data);
DB::table('test')->where('id',1)->update(['edit'=>-1]);
dd($test);
return redirect()->back();
}
catch (\Exception $e) {
return ("Ошибка обновления в БД. Возможно, данная пара ИМЕНИ/ПРЕФИКСА уже существует");
}
} else {
return 'Ошибка';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment