diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index a319789fe80d..7e49014e1e0a 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -498,26 +498,30 @@ public function transaction(Closure $callback) * Start a new database transaction. * * @return void - * @throws Exception + * + * @throws \Exception */ public function beginTransaction() { - ++$this->transactions; - - if ($this->transactions == 1) { + if ($this->transactions == 0) { try { $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()) { + } elseif ($this->transactions >= 1 && $this->queryGrammar->supportsSavepoints()) { $this->pdo->exec( - $this->queryGrammar->compileSavepoint('trans'.$this->transactions) + $this->queryGrammar->compileSavepoint('trans'.($this->transactions + 1)) ); } + ++$this->transactions; + $this->fireConnectionEvent('beganTransaction'); } @@ -866,6 +870,8 @@ public function getReadPdo() * * @param \PDO|null $pdo * @return $this + * + * @throws \RuntimeException */ public function setPdo($pdo) { diff --git a/tests/Database/DatabaseConnectionTest.php b/tests/Database/DatabaseConnectionTest.php index 97d71ef9f8b8..50646347a02d 100755 --- a/tests/Database/DatabaseConnectionTest.php +++ b/tests/Database/DatabaseConnectionTest.php @@ -111,18 +111,48 @@ public function testAffectingStatementProperlyCallsPDO() $this->assertTrue(is_numeric($log[0]['time'])); } - public function testTransactionsDecrementedOnTransactionException() + public function testTransactionLevelNotIncrementedOnTransactionException() { $pdo = $this->getMock('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); try { $connection->beginTransaction(); - } catch (ErrorException $e) { + } catch (Exception $e) { $this->assertEquals(0, $connection->transactionLevel()); } } + public function testBeginTransactionMethodRetriesOnFailure() + { + $pdo = $this->getMock('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(); + $this->assertEquals(1, $connection->transactionLevel()); + } + + public function testBeginTransactionMethodNeverRetriesIfWithinTransaction() + { + $pdo = $this->getMock('DatabaseConnectionTestMockPDO'); + $pdo->expects($this->once())->method('beginTransaction'); + $pdo->expects($this->once())->method('exec')->will($this->throwException(new Exception)); + $connection = $this->getMockConnection([], $pdo); + $queryGrammar = $this->getMock('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()); + } + } + /** * @expectedException RuntimeException */