Laravel DB:与Firebird连接的事务



我在Laravel事务中遇到了一些问题。

  • Laravel 9+
  • PHP 8+
  • 火鸟2.5

我有两个数据库连接MySQL(默认(和Firebird。MySQL运行良好,如下所示。我得到了连接数据。

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

当我尝试与我的另一个连接("firebird"(一起使用时,它总是抛出"已经有一个活动的事务">错误。

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

我也尝试过这个版本,但如果我使用"火鸟"连接,我会得到同样的错误:

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

如果我忽略了事务,那么两者都可以正常工作,但如果出现任何错误,我希望使用回滚。有什么想法吗?我陷入了困境。

Firebird总是使用事务。一旦您在数据库中进行更改,事务就会立即启动,并且在提交之前,事务会一直为该会话打开。使用您的代码,它很简单:

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

当您在SQL Server中开始trans时,并不意味着您现在就开始事务。您已经处于事务中,因为您已连接到数据库!begin tran真正做的是禁用";在每个语句处自动提交";,这是SQL Server中的默认状态(除非另有指定(。

commit-tran分别提交并将连接恢复为"trans";在每个语句处自动提交";状态

在任何数据库中,当您连接时,您已经处于事务中。数据库就是这样。例如,在Firebird中,即使只运行查询,也可以执行提交或回滚。

另一方面,一些数据库和连接库允许您使用";在每个语句处自动提交";连接状态,这就是SQL Server正在执行的操作。尽管这个功能可能很有用,但它并不是很说教,会让初学者认为自己是";而不是在交易中";。

解决方案:
当您在"config/database.php"中定义"Firebird"连接时,需要关闭自动提交(PDO::ATTR_AUTOCOMMIT(示例:

'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,
)
],

然后您可以使用Laravel交易,如:

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

或者你也可以使用这个,这样可以自动进行提交或回滚:

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

但别忘了!如果你这样做,你必须每次启动交易!即使您只是选择一些数据。

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

否则您将得到SQL错误,如:

SQLSTATE[HY000]:一般错误:-901无效事务句柄(需要显式事务启动(

谢谢大家!

最新更新