From 5250bc5007f7edf84d181987636e44e109eb692f Mon Sep 17 00:00:00 2001 From: eske Date: Tue, 16 Jun 2026 18:32:29 +0200 Subject: [PATCH 1/2] fix(db): trigger rollbacks when closing connection --- src/Illuminate/Database/Connection.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 49a0ccfae7e2..511f45ac1436 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -1061,6 +1061,10 @@ public function reconnectIfMissingConnection() */ public function disconnect() { + if ($this->transactions > 0) { + $this->transactionsManager?->rollback($this->getName(), 0); + } + $this->setPdo(null)->setReadPdo(null); } From 44ba5c6b8b5d2594ad83cf8613534f80caed6118 Mon Sep 17 00:00:00 2001 From: eske Date: Tue, 16 Jun 2026 18:32:34 +0200 Subject: [PATCH 2/2] test(db): rollbacks are triggered when disconnecting --- tests/Database/DatabaseConnectionTest.php | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/Database/DatabaseConnectionTest.php b/tests/Database/DatabaseConnectionTest.php index f91806bc6a65..f9a88ddd9e91 100755 --- a/tests/Database/DatabaseConnectionTest.php +++ b/tests/Database/DatabaseConnectionTest.php @@ -7,6 +7,7 @@ use Exception; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\Connection; +use Illuminate\Database\DatabaseTransactionsManager; use Illuminate\Database\Events\QueryExecuted; use Illuminate\Database\Events\TransactionBeginning; use Illuminate\Database\Events\TransactionCommitted; @@ -252,6 +253,45 @@ public function testSwapPDOWithOpenTransactionResetsTransactionLevel() $this->assertEquals(0, $connection->transactionLevel()); } + public function testDisconnectRollsBackTransactionsManagerWhenTransactionIsActive() + { + $pdo = $this->createMock(DatabaseConnectionTestMockPDO::class); + $connection = $this->getMockConnection(['getName'], $pdo); + $connection->method('getName')->willReturn('name'); + $connection->setTransactionManager($manager = new DatabaseTransactionsManager); + + $connection->beginTransaction(); + + $connection->disconnect(); + + $this->assertCount(0, $manager->getPendingTransactions()); + $this->assertEquals(0, $connection->transactionLevel()); + } + + public function testDisconnectMidTransactionDiscardsStaleAfterCommitCallbacks() + { + $pdo = $this->createMock(DatabaseConnectionTestMockPDO::class); + $connection = $this->getMockConnection(['getName'], $pdo); + $connection->method('getName')->willReturn('name'); + $connection->setReconnector(function ($connection) { + $connection->setPdo($this->createMock(DatabaseConnectionTestMockPDO::class)); + }); + $connection->setTransactionManager($manager = new DatabaseTransactionsManager); + + $fired = 0; + $connection->beginTransaction(); + $manager->addCallback(function () use (&$fired) { + $fired++; + }); + + $connection->disconnect(); + + $connection->beginTransaction(); + $connection->commit(); + + $this->assertSame(0, $fired); + } + public function testBeganTransactionFiresEventsIfSet() { $pdo = $this->createMock(DatabaseConnectionTestMockPDO::class);