Eloquent ORM довольно приятный, хотя мне интересно, есть ли простой способ настроить транзакции MySQL с помощью innoDB так же, как PDO, или если мне придется расширить ORM, чтобы сделать это возможным?
Вы можете сделать это:
DB::transaction(function() {
//
});
Все внутри Closure выполняется внутри транзакции. Если произойдет исключение, он автоматически откатится.
Если вам не нравятся анонимные функции:
try {
DB::connection()->pdo->beginTransaction();
// database queries here
DB::connection()->pdo->commit();
} catch (\PDOException $e) {
// Woopsy
DB::connection()->pdo->rollBack();
}
Обновление. Для laravel 4 объект pdo
не является общедоступным, поэтому:
try {
DB::beginTransaction();
// database queries here
DB::commit();
} catch (\PDOException $e) {
// Woopsy
DB::rollBack();
}
DB::beginTransaction()
и DB::commit()
& DB::rollback()
. Это было бы немного чище.
Если вы хотите использовать Eloquent, вы также можете использовать этот
Это всего лишь образец кода из моего проекта
/*
* Saving Question
*/
$question = new Question;
$questionCategory = new QuestionCategory;
/*
* Insert new record for question
*/
$question->title = $title;
$question->user_id = Auth::user()->user_id;
$question->description = $description;
$question->time_post = date('Y-m-d H:i:s');
if(Input::has('expiredtime'))
$question->expired_time = Input::get('expiredtime');
$questionCategory->category_id = $category;
$questionCategory->time_added = date('Y-m-d H:i:s');
DB::transaction(function() use ($question, $questionCategory) {
$question->save();
/*
* insert new record for question category
*/
$questionCategory->question_id = $question->id;
$questionCategory->save();
});
Если вы хотите избежать закрытий и счастливы использовать фасады, следующее держит вещи приятными и чистыми:
\DB::beginTransaction();
$user = \Auth::user();
$user->fill($request->all());
$user->push();
\DB::commit();
Если какие-либо утверждения терпят неудачу, commit никогда не ударит, и транзакция не будет обрабатываться.
Я уверен, что вы не ищете решение для закрытия, попробуйте это для более компактного решения
try{
DB::beginTransaction();
/*
* Your DB code
* */
DB::commit();
}catch(\Exception $e){
DB::rollback();
}
По какой-то причине довольно сложно найти эту информацию в любом месте, поэтому я решил опубликовать ее здесь, так как моя проблема, связанная с транзакциями Eloquent, точно меняла это.
После чтения ЭТО ответ stackoverflow, я понял, что мои таблицы базы данных использовали MyISAM вместо InnoDB.
Чтобы транзакции работали на Laravel (или где-либо еще, как кажется), требуется, чтобы ваши таблицы были настроены на использование InnoDB
Почему?
Цитата MySQL Транзакции и Атомные операции docs (здесь):
Сервер MySQL (версия 3.23-max и все версии 4.0 и выше) поддерживает транзакции с транзакционными системами хранения данных InnoDB и BDB. InnoDB обеспечивает полное соответствие требованиям ACID. См. Главу 14 "Двигатели хранения". Информацию о различиях InnoDB от стандартного SQL в отношении обработки ошибок транзакций см. В разделе 14.2.11 "Обработка ошибок InnoDB".
Другие нетранзакционные системы хранения в MySQL Server (такие как MyISAM) следуют другой парадигме для целостности данных, называемой "атомарные операции". В транзакционных условиях таблицы MyISAM эффективно работают в режиме autocommit = 1. Атомные операции часто обеспечивают сопоставимую целостность с более высокой производительностью.
Поскольку MySQL Server поддерживает обе парадигмы, вы можете решить, лучше ли ваши приложения обслуживать скорость атомных операций или использование транзакционных функций. Этот выбор можно сделать на основе таблицы.
Если произойдет какое-либо исключение, транзакция автоматически откатится.
Laravel Основной формат транзакции
try{
DB::beginTransaction();
/*
* SQL operation one
* SQL operation two
..................
..................
* SQL operation n */
DB::commit();
/* Transaction successful. */
}catch(\Exception $e){
DB::rollback();
/* Transaction failed. */
}