【发布时间】:2021-07-19 04:30:48
【问题描述】:
我对 Laravel 比较陌生,我想了解更多关于 API 控制器方法(即在 routes/api.php 中定义)中以下代码的行为。
DB::connection($dbName)->beginTransaction();
假设两个人同时访问服务器并创建了两个控制器实例。现在两个实例都调用DB::connection($dbName)->beginTransaction();) 并在提交前执行一些代码。
为了更清楚地描述这种情况,两个人 A 和 B 都访问同一个 Laravel 服务器,具有同一个控制器类的两个实例。两个控制器实例都从同一个 IP 地址访问同一个 DB,并执行涉及beginTransaction 的相同代码段。
根据我目前的信息,有两种可能发生的事情:
(1) 它们被视为两个不同的事务,诸如 lastInsertId 之类的东西是分开维护的。这是所需的行为,但我无法理解控制器的两个不同实例是如何在内部识别的。根据对 Laravel 源代码的粗略查看,它似乎只读取特定数据库连接的配置文件,这对于控制器的两个实例都是相同的。
(2) 它们被视为相同的事务,这不是期望的行为。我将不得不想办法让它像(1)中描述的那样工作
目前我没有足够的环境来准确测试并发控制器实例的行为,所以我必须在这里提出问题。
我已阅读 https://laravel.com/docs/8.x/database#database-transactions,但它并没有告诉我们是 (1) 还是 (2)。
【问题讨论】:
-
作为一个不了解 laravel 的人,我会在两个连接中都使用 select CONNECTION_ID() (mysql too)。如果您最终得到不同的数字,则为 (1)。
-
每个并发请求都在它自己的 PHP 线程/进程中处理,并且每个事务都与其他事务隔离。每个控制器实例都将存在于该线程/进程中。 PHP 不像 Java EE 或 .NET,其中服务器也是对象的容器,因此可以跨请求共享对象
-
@apokryfos 谢谢你的回答。这是否意味着 PHP 的默认行为必须是 case (1) 有或没有 Laravel?
-
是的,在 PHP 中,每个请求都是一个独立的实体,它在自己的“沙箱”中初始化任何东西。有 ways 在 PHP 进程之间共享信息,但它们的级别非常低,在实践中很少使用。还有一些方法可以将 MySQL 连接池化,但即使您每次从池中获取连接时都使用这些连接,它也会被重置。
标签: mysql laravel transactions