skip to Main Content

I have some trouble with the Laravel transaction.

  • Laravel 9+
  • PHP 8+
  • Firebird 2.5

I have two DB connection MySQL (default) and Firebird. MySQL works fine, like this. I get the connection data.

DB::transaction(function ($conn) use ($request) { 
 dd($conn)
});

When I try to use with my other connection (‘firebird’), it always throws "There is already an active transaction" error.

DB::connection('firebird')->transaction(function ($conn) use ($request) {
 dd($conn);
 $conn->table('A')->insert();
 $conn->table('B')->insert();
 $conn->table('C')->insert();
});

I tried this version too, but I get the same error if I use the ‘firebird’ connection:

DB::connection('firebird')->beginTransaction();

If I leave out the transaction, both are working just fine, but I want to use rollback if there is any error. Any thoughts why? I’m stuck at this.

2

Answers


  1. Chosen as BEST ANSWER

    The solution:
    Need to turn off auto commit(PDO::ATTR_AUTOCOMMIT), when you define the 'Firebird' connection in 'config/database.php' Example:

    'firebird' => [
            'driver'   => 'firebird',
            'host'     => env('DB_FIREBIRD_HOST', '127.0.0.1'),
            'port'     => env('DB_FIREBIRD_PORT', '3050'),
            'database' => env('DB_FIREBIRD_DATABASE', 
              'pathtodbDEFAULT.DATABASE'),
            'username' => env('DB_FIREBIRD_USERNAME', 'username'),
            'password' => env('DB_FIREBIRD_PASSWORD', 'password'),
            'charset'  => env('DB_FIREBIRD_CHARSET', 'UTF8'),
            'options' => array(
                PDO::ATTR_PERSISTENT => false,
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_AUTOCOMMIT => false,
            )
        ],
    

    Then you can use Laravel transactions like:

    try{
        DB::connection('firebird')->beginTransaction();
        DB::connection('firebird')->insert();
    
        DB::connection('firebird')->commit();
    } catch (Exception $exception) {
        DB::connection('firebird')->rollBack();
        throw $exception;
    }
    

    Or you can use this too and this do the commit or rollback automatic:

    DB::connection('firebird')->transaction(function () use 
      ($request) {
            DB::connection('firebird')->insert($request);
    })
    

    But dont forget! If you do this, you must start the transaction every time! Even when you are just Select some data.

    DB::connection('firebird')->beginTransaction();
    

    or you will get SQL error like:

    SQLSTATE[HY000]: General error: -901 invalid transaction handle (expecting explicit transaction start)

    Thank you everybody!


  2. Firebird always uses transactions. The transaction is started as soon as you make a change in the database and remains open for that session until you commit. Using your code, it’s simply:

    DB::connection('firebird')->insert();
    DB::connection('firebird')->commit() or rollback();
    

    When you do begin tran in SQL Server, it does not mean that you’re starting the transaction now. You are already in transaction, since you are connected to the database! What begin tran really does is disable the "auto-commit at each statement", which is the default state in SQL Server (unless otherwise specified).

    Respectively, commit tran commits and reverts the connection to "auto-commit at each statement" state.

    In any database, when you are connected, you are already in transaction. This is how databases are. For instance, in Firebird, you can perform a commit or rollback even if only ran a query.

    Some databases and connection libs, in the other hand, let you use the "auto-commit at each statement" state of connection, which is what SQL Server is doing. As useful as that feature might be, it’s not very didactic and lead beginners to think they are "not in a transaction".

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search