Laravel database transactions for data integrity

Carlos Mendez Jan 2026
3 tabs
<?php

use Illuminate\Support\Facades\DB;

public function createOrder(array $items, User $user)
{
    return DB::transaction(function () use ($items, $user) {
        // Create order
        $order = Order::create([
            'user_id' => $user->id,
            'total' => 0,
        ]);

        $total = 0;

        foreach ($items as $item) {
            // Create order items
            $orderItem = $order->items()->create([
                'product_id' => $item['product_id'],
                'quantity' => $item['quantity'],
                'price' => $item['price'],
            ]);

            // Update inventory
            $product = Product::findOrFail($item['product_id']);

            if ($product->stock < $item['quantity']) {
                throw new \Exception("Insufficient stock for {$product->name}");
            }

            $product->decrement('stock', $item['quantity']);

            $total += $item['price'] * $item['quantity'];
        }

        // Update order total
        $order->update(['total' => $total]);

        return $order;
    }, 3); // Retry 3 times on deadlock
}
3 files · php Explain with highlit

Database transactions ensure multiple database operations succeed or fail together, maintaining data consistency. I wrap related operations in DB::transaction() which automatically commits on success and rolls back on exceptions. For manual control, I use DB::beginTransaction(), DB::commit(), and DB::rollBack(). Nested transactions use savepoints internally. The transaction closure receives attempts count for retry logic. Eloquent events fire after transactions commit when using $afterCommit property. For distributed transactions across services, I implement saga patterns. Transactions prevent partial updates that leave data in inconsistent states—critical for payment processing, inventory management, or multi-table updates. Proper transaction usage is fundamental to data integrity.