The Eloquent ORM is quite nice, though I'm wondering if there is an easy way to setup MySQL transactions using innoDB in the same fashion as PDO, or if I would have to extend the ORM to make this possible?
8 Answers
You can do this:
DB::transaction(function() {
//
});
Everything inside the Closure executes within a transaction. If an exception occurs it will rollback automatically.

- 58,936
- 21
- 171
- 212
-
3Inside the closure I can call queries in an class? It will works? – Rafael Soufraz May 14 '15 at 16:56
-
2Sadly it is not working for me if I am creating instance of different models who are storing record in their own relevant methods. – Volatil3 Aug 28 '15 at 11:22
-
1If I catch an exception inside my transaction (for generating error messages, etc), do I need to re-emit the exception to have the rollback occur? – alexw Feb 19 '16 at 19:04
-
8Good answer but a couple things caught me out: 1. You need to add "use DB;" to do this e.g. at the top of your model file 2. Unlike JS, you don't get access to local variables in the parent scope unless you explicitly pass them in, you need to add the "use" construct thusly... DB::transaction(function() use ($user) { ...stuffs referencing $user... }); – Polsonby Jun 22 '16 at 08:25
-
@Polsonby perfect, better move to an answer. – Hamid Asghari Sep 25 '17 at 12:33
-
Transactions do not work at all unless you use raw queries or the DB object no matter how they are started. – dfmiller Aug 14 '18 at 15:02
-
1"It will roll back" -- "roll back" needs to be separate words in that case (verb). It's only joined as a noun or adjective. You wouldn't wakeup in the morning, raiseup children or turnon the light, would you? – GeneC Dec 27 '20 at 18:49
-
2As documentation says: "The DB facade's transaction methods control the transactions for both the query builder and Eloquent ORM." -> https://laravel.com/docs/8.x/database#database-transactions. – accexs Feb 02 '21 at 18:19
If you don't like anonymous functions:
try {
DB::connection()->pdo->beginTransaction();
// database queries here
DB::connection()->pdo->commit();
} catch (\PDOException $e) {
// Woopsy
DB::connection()->pdo->rollBack();
}
Update: For laravel 4, the pdo
object isn't public anymore so:
try {
DB::beginTransaction();
// database queries here
DB::commit();
} catch (\PDOException $e) {
// Woopsy
DB::rollBack();
}

- 863
- 5
- 22

- 14,299
- 26
- 93
- 133
-
16You can also use the shortcut methods `DB::beginTransaction()` & `DB::commit()` & `DB::rollback()`. That would be a little cleaner. – Flori Feb 03 '14 at 22:59
-
2Please update to use @Flori suggestion. It is cleaner. Also, moving the new answer upwards will make your answer less confusing. I used first method before coming back for second one. – frostymarvelous Feb 22 '14 at 22:52
-
For older version of Laravel, You might need: `DB::connection()->getPdo()->beginTransaction();` – instead Mar 08 '19 at 16:44
-
I personally think the `DB::transaction` with callback is even cleaner but the drawback is that if you need to specify different handlers for different exceptions you will have to go back to try/catch technique – OzzyTheGiant Jun 11 '20 at 21:50
If you want to avoid closures, and happy to use facades, the following keeps things nice and clean:
try {
\DB::beginTransaction();
$user = \Auth::user();
$user->fill($request->all());
$user->push();
\DB::commit();
} catch (Throwable $e) {
\DB::rollback();
}
If any statements fail, commit will never hit, and the transaction won't process.

- 54,599
- 30
- 149
- 186
-
If any statements fail, *subsequent* statements won't run. You still need to explicitly roll back the transaction. – Jason Oct 15 '19 at 13:26
-
2@Jason I've updated the answer. I was in two minds about if I should, for most (all?) database engines, when the connection is terminated any transactional queries not committed won't be committed. However, I agree with what you are saying, and probably best to be explicit – Chris Oct 15 '19 at 22:34
If you want to use Eloquent, you also can use this
This is just sample code from my project
/*
* 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();
});

- 11,869
- 8
- 42
- 48
-
The `question->id` expression at the transaction callback returns zero. – Christos Papoulas Apr 04 '19 at 07:49
-
@ChristosPapoulas did you mean, we can not get the auto increment id in transaction? – hellojinjie May 31 '19 at 09:55
-
-
-
Can we also put `Mail::to()` inside the closure? Or just DB related transactions? – Blues Clues Jun 22 '21 at 15:35
-
1@Jonjie I believe You can, but it's more better after the transaction commited to DB – Aditya Kresna Permana Jun 27 '21 at 09:12
-
@AdityaKresnaPermana yup, I tried it and it's working inside the closure :) – Blues Clues Jun 29 '21 at 03:18
I'm Sure you are not looking for a closure solution, try this for a more compact solution
try{
DB::beginTransaction();
/*
* Your DB code
* */
DB::commit();
}catch(\Exception $e){
DB::rollback();
}

- 9,683
- 3
- 51
- 41
For some reason it is quite difficult to find this information anywhere, so I decided to post it here, as my issue, while related to Eloquent transactions, was exactly changing this.
After reading THIS stackoverflow answer, I realized my database tables were using MyISAM instead of InnoDB.
For transactions to work on Laravel (or anywhere else as it seems), it is required that your tables are set to use InnoDB
Why?
Quoting MySQL Transactions and Atomic Operations docs (here):
MySQL Server (version 3.23-max and all versions 4.0 and above) supports transactions with the InnoDB and BDB transactional storage engines. InnoDB provides full ACID compliance. See Chapter 14, Storage Engines. For information about InnoDB differences from standard SQL with regard to treatment of transaction errors, see Section 14.2.11, “InnoDB Error Handling”.
The other nontransactional storage engines in MySQL Server (such as MyISAM) follow a different paradigm for data integrity called “atomic operations.” In transactional terms, MyISAM tables effectively always operate in autocommit = 1 mode. Atomic operations often offer comparable integrity with higher performance.
Because MySQL Server supports both paradigms, you can decide whether your applications are best served by the speed of atomic operations or the use of transactional features. This choice can be made on a per-table basis.
If any exception occurs, the transaction will rollback automatically.
Laravel Basic transaction format
try{
DB::beginTransaction();
/*
* SQL operation one
* SQL operation two
..................
..................
* SQL operation n */
DB::commit();
/* Transaction successful. */
}catch(\Exception $e){
DB::rollback();
/* Transaction failed. */
}

- 2,761
- 23
- 29
The best and clear way:
DB::beginTransaction();
try {
DB::insert(...);
DB::insert(...);
DB::insert(...);
DB::commit();
// all good
} catch (\Exception $e) {
DB::rollback();
// something went wrong
}

- 7,360
- 4
- 18
- 33