diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index e920e8fa4918..cd8a8a685fea 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -601,22 +601,25 @@ public function transaction(Closure $callback, $attempts = 1) */ public function beginTransaction() { - ++$this->transactions; - - if ($this->transactions == 1) { + if ($this->transactions == 0) { try { - $this->getPdo()->beginTransaction(); + $this->pdo->beginTransaction(); } catch (Exception $e) { - --$this->transactions; - - throw $e; + if ($this->causedByLostConnection($e)) { + $this->reconnect(); + $this->pdo->beginTransaction(); + } else { + throw $e; + } } - } elseif ($this->transactions > 1 && $this->queryGrammar->supportsSavepoints()) { - $this->getPdo()->exec( - $this->queryGrammar->compileSavepoint('trans'.$this->transactions) + } elseif ($this->transactions >= 1 && $this->queryGrammar->supportsSavepoints()) { + $this->pdo->exec( + $this->queryGrammar->compileSavepoint('trans'.($this->transactions + 1)) ); } + ++$this->transactions; + $this->fireConnectionEvent('beganTransaction'); } diff --git a/tests/Database/DatabaseConnectionTest.php b/tests/Database/DatabaseConnectionTest.php index 71b74c1b2049..bb40bdfe4012 100755 --- a/tests/Database/DatabaseConnectionTest.php +++ b/tests/Database/DatabaseConnectionTest.php @@ -114,15 +114,46 @@ public function testAffectingStatementProperlyCallsPDO() $this->assertTrue(is_numeric($log[0]['time'])); } - public function testTransactionsDecrementedOnTransactionException() + public function testTransactionLevelNotIncrementedOnTransactionException() { $pdo = $this->createMock('DatabaseConnectionTestMockPDO'); - $pdo->expects($this->once())->method('beginTransaction')->will($this->throwException(new ErrorException('MySQL server has gone away'))); + $pdo->expects($this->once())->method('beginTransaction')->will($this->throwException(new Exception)); $connection = $this->getMockConnection([], $pdo); - $this->setExpectedException('ErrorException', 'MySQL server has gone away'); + try { + $connection->beginTransaction(); + } catch (Exception $e) { + $this->assertEquals(0, $connection->transactionLevel()); + } + } + + public function testBeginTransactionMethodRetriesOnFailure() + { + $pdo = $this->createMock('DatabaseConnectionTestMockPDO'); + $pdo->expects($this->exactly(2))->method('beginTransaction'); + $pdo->expects($this->at(0))->method('beginTransaction')->will($this->throwException(new ErrorException('server has gone away'))); + $connection = $this->getMockConnection(['reconnect'], $pdo); + $connection->expects($this->once())->method('reconnect'); $connection->beginTransaction(); - $connection->disconnect(); - $this->assertNull($connection->getPdo()); + $this->assertEquals(1, $connection->transactionLevel()); + } + + public function testBeginTransactionMethodNeverRetriesIfWithinTransaction() + { + $pdo = $this->createMock('DatabaseConnectionTestMockPDO'); + $pdo->expects($this->once())->method('beginTransaction'); + $pdo->expects($this->once())->method('exec')->will($this->throwException(new Exception)); + $connection = $this->getMockConnection(['reconnect'], $pdo); + $queryGrammar = $this->createMock('Illuminate\Database\Query\Grammars\Grammar'); + $queryGrammar->expects($this->once())->method('supportsSavepoints')->will($this->returnValue(true)); + $connection->setQueryGrammar($queryGrammar); + $connection->expects($this->never())->method('reconnect'); + $connection->beginTransaction(); + $this->assertEquals(1, $connection->transactionLevel()); + try { + $connection->beginTransaction(); + } catch (Exception $e) { + $this->assertEquals(1, $connection->transactionLevel()); + } } public function testCantSwapPDOWithOpenTransaction()