PHP

Ensuring Data Integrity with Eloquent Transactions

Learn how to use database transactions in Laravel Eloquent to group multiple database operations, ensuring atomicity, consistency, isolation, and durability (ACID).

use Illuminate\Support\Facades\DB;
use App\Models\Order;
use App\Models\OrderItem;
use Exception;

try {
    DB::transaction(function () {
        // Step 1: Create a new order
        $order = Order::create([
            'user_id' => 1,
            'total_amount' => 0, // Will update later
            'status' => 'pending',
        ]);

        // Simulate multiple order items
        $itemsData = [
            ['product_id' => 101, 'quantity' => 2, 'price' => 15.00],
            ['product_id' => 102, 'quantity' => 1, 'price' => 25.00],
            // Imagine a third item fails
            // ['product_id' => 999, 'quantity' => 1, 'price' => 50.00],
        ];

        $total = 0;
        foreach ($itemsData as $itemData) {
            // Step 2: Create order items for the order
            $orderItem = new OrderItem($itemData);
            $orderItem->order_id = $order->id;
            $orderItem->save();
            $total += ($itemData['quantity'] * $itemData['price']);
        }

        // Step 3: Update order total
        $order->total_amount = $total;
        $order->save();

        // Simulate an error after successful operations to test rollback
        // throw new Exception('Simulated error during transaction.');

        echo "Order and order items created successfully!
";
    });
} catch (Exception $e) {
    // The transaction will automatically be rolled back here
    echo "Transaction failed: " . $e->getMessage() . "
";
    echo "Database changes were rolled back.
";
}

// Alternatively, using the Model's transaction method (PHP 8+ required for static closure binding)
// Order::transaction(function () {
//     $order = Order::create(['user_id' => 2, 'total_amount' => 0, 'status' => 'pending']);
//     // ... create order items ...
//     $order->total_amount = 100;
//     $order->save();
// });
How it works: Database transactions are crucial for maintaining data integrity when performing multiple related database operations. By wrapping these operations in `DB::transaction()` (or `$model->getConnection()->transaction()`), you ensure that either all operations succeed and are committed, or if any fail, all previous operations within that transaction are rolled back, leaving the database in its original state. This prevents partial updates and inconsistent data.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs