Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

[DBAL-81] Add possibility to set the auto-commit mode for a connection #409

Merged
merged 5 commits into from 5 months ago

3 participants

Steve Müller doctrinebot Benjamin Eberlei
Steve Müller
Collaborator

This PR makes auto-commit mode configurable for a connection (as proposed in DBAL-81).
The implementation adds methods to get and set the auto-commit mode on a connection object. When NOT in auto-commit mode, each commit() and rollBack() call automatically start a new transaction after the operation is finished. Aditionally a call to connect() starts a new transaction if not already connected.
When IN auto-commit mode, the behaviour is the same as it is with the current implementation.
When switching auto-commit mode, all current active transactions are committed.

doctrinebot
Collaborator

Hello,

thank you for creating this pull request. I have automatically opened an issue
on our Jira Bug Tracker for you. See the issue link:

http://www.doctrine-project.org/jira/browse/DBAL-660

We use Jira to track the state of pull requests and the versions they got
included in.

lib/Doctrine/DBAL/Connection.php
((14 lines not shown))
  389
+
  390
+    /**
  391
+     * Sets auto-commit mode for this connection.
  392
+     *
  393
+     * If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual
  394
+     * transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either
  395
+     * the method commit or the method rollback. By default, new connections are in auto-commit mode.
  396
+     *
  397
+     * NOTE: If this method is called during a transaction and the auto-commit mode is changed, the transaction is
  398
+     * committed. If this method is called and the auto-commit mode is not changed, the call is a no-op.
  399
+     *
  400
+     * @param boolean $autoCommit True to enable auto-commit mode; false to disable it.
  401
+     *
  402
+     * @see   getAutoCommit
  403
+     */
  404
+    public function setAutoCommit($autoCommit)
1
Benjamin Eberlei Owner

We should offer a way to set autocommit during creation of the connection already, to avoid having to think about the implications of calling this method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Benjamin Eberlei
Owner

great!

Steve Müller
Collaborator

@beberlei Made auto-commit mode configurable via the configuration container.

lib/Doctrine/DBAL/Connection.php
@@ -1095,6 +1150,28 @@ public function commit()
1095 1150
         }
1096 1151
 
1097 1152
         --$this->_transactionNestingLevel;
  1153
+
  1154
+        if (false === $this->autoCommit && 0 === $this->_transactionNestingLevel) {
  1155
+            $this->beginTransaction();
  1156
+        }
  1157
+    }
  1158
+
  1159
+    /**
  1160
+     * Commits all current nesting transactions.
  1161
+     */
  1162
+    public function commitAll()
2
Benjamin Eberlei Owner

private please.

Steve Müller Collaborator

done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Connection.php
@@ -1141,6 +1222,24 @@ public function rollBack()
1141 1222
     }
1142 1223
 
1143 1224
     /**
  1225
+     * Cancel any database changes done during all current nesting transactions.
  1226
+     */
  1227
+    public function rollBackAll()
2
Benjamin Eberlei Owner

private

Steve Müller Collaborator

removed because it is unused when private.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Steve Müller
Collaborator

@beberlei this is ready now from my point of view. You can have another look on it when you have time to.

Benjamin Eberlei beberlei merged commit 95b196f into from November 11, 2013
Benjamin Eberlei beberlei closed this November 11, 2013
Steve Müller deeky666 referenced this pull request in doctrine/DoctrineBundle January 04, 2014
Merged

[DBAL-81] Add auto-commit DBAL configuration option #236

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
32  lib/Doctrine/DBAL/Configuration.php
@@ -117,4 +117,36 @@ public function getFilterSchemaAssetsExpression()
117 117
 
118 118
         return null;
119 119
     }
  120
+
  121
+    /**
  122
+     * Sets the default auto-commit mode for connections.
  123
+     *
  124
+     * If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual
  125
+     * transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either
  126
+     * the method commit or the method rollback. By default, new connections are in auto-commit mode.
  127
+     *
  128
+     * @param boolean $autoCommit True to enable auto-commit mode; false to disable it.
  129
+     *
  130
+     * @see   getAutoCommit
  131
+     */
  132
+    public function setAutoCommit($autoCommit)
  133
+    {
  134
+        $this->_attributes['autoCommit'] = (boolean) $autoCommit;
  135
+    }
  136
+
  137
+    /**
  138
+     * Returns the default auto-commit mode for connections.
  139
+     *
  140
+     * @return boolean True if auto-commit mode is enabled by default for connections, false otherwise.
  141
+     *
  142
+     * @see    setAutoCommit
  143
+     */
  144
+    public function getAutoCommit()
  145
+    {
  146
+        if (isset($this->_attributes['autoCommit'])) {
  147
+            return $this->_attributes['autoCommit'];
  148
+        }
  149
+
  150
+        return true;
  151
+    }
120 152
 }
81  lib/Doctrine/DBAL/Connection.php
@@ -118,6 +118,13 @@ class Connection implements DriverConnection
118 118
     private $_isConnected = false;
119 119
 
120 120
     /**
  121
+     * The current auto-commit mode of this connection.
  122
+     *
  123
+     * @var boolean
  124
+     */
  125
+    private $autoCommit = true;
  126
+
  127
+    /**
121 128
      * The transaction nesting level.
122 129
      *
123 130
      * @var integer
@@ -225,6 +232,7 @@ public function __construct(array $params, Driver $driver, Configuration $config
225 232
         $this->_platform->setEventManager($eventManager);
226 233
 
227 234
         $this->_transactionIsolationLevel = $this->_platform->getDefaultTransactionIsolationLevel();
  235
+        $this->autoCommit = $config->getAutoCommit();
228 236
     }
229 237
 
230 238
     /**
@@ -356,6 +364,10 @@ public function connect()
356 364
         $this->_conn = $this->_driver->connect($this->_params, $user, $password, $driverOptions);
357 365
         $this->_isConnected = true;
358 366
 
  367
+        if (false === $this->autoCommit) {
  368
+            $this->beginTransaction();
  369
+        }
  370
+
359 371
         if ($this->_eventManager->hasListeners(Events::postConnect)) {
360 372
             $eventArgs = new Event\ConnectionEventArgs($this);
361 373
             $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
@@ -365,6 +377,49 @@ public function connect()
365 377
     }
366 378
 
367 379
     /**
  380
+     * Returns the current auto-commit mode for this connection.
  381
+     *
  382
+     * @return boolean True if auto-commit mode is currently enabled for this connection, false otherwise.
  383
+     *
  384
+     * @see    setAutoCommit
  385
+     */
  386
+    public function isAutoCommit()
  387
+    {
  388
+        return true === $this->autoCommit;
  389
+    }
  390
+
  391
+    /**
  392
+     * Sets auto-commit mode for this connection.
  393
+     *
  394
+     * If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual
  395
+     * transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either
  396
+     * the method commit or the method rollback. By default, new connections are in auto-commit mode.
  397
+     *
  398
+     * NOTE: If this method is called during a transaction and the auto-commit mode is changed, the transaction is
  399
+     * committed. If this method is called and the auto-commit mode is not changed, the call is a no-op.
  400
+     *
  401
+     * @param boolean $autoCommit True to enable auto-commit mode; false to disable it.
  402
+     *
  403
+     * @see   isAutoCommit
  404
+     */
  405
+    public function setAutoCommit($autoCommit)
  406
+    {
  407
+        $autoCommit = (boolean) $autoCommit;
  408
+
  409
+        // Mode not changed, no-op.
  410
+        if ($autoCommit === $this->autoCommit) {
  411
+            return;
  412
+        }
  413
+
  414
+        $this->autoCommit = $autoCommit;
  415
+
  416
+        // Commit all currently active transactions if any when switching auto-commit mode.
  417
+        if (true === $this->_isConnected && 0 !== $this->_transactionNestingLevel) {
  418
+            $this->commitAll();
  419
+        }
  420
+    }
  421
+
  422
+    /**
368 423
      * Sets the fetch mode.
369 424
      *
370 425
      * @param integer $fetchMode
@@ -1095,6 +1150,28 @@ public function commit()
1095 1150
         }
1096 1151
 
1097 1152
         --$this->_transactionNestingLevel;
  1153
+
  1154
+        if (false === $this->autoCommit && 0 === $this->_transactionNestingLevel) {
  1155
+            $this->beginTransaction();
  1156
+        }
  1157
+    }
  1158
+
  1159
+    /**
  1160
+     * Commits all current nesting transactions.
  1161
+     */
  1162
+    private function commitAll()
  1163
+    {
  1164
+        while (0 !== $this->_transactionNestingLevel) {
  1165
+            if (false === $this->autoCommit && 1 === $this->_transactionNestingLevel) {
  1166
+                // When in no auto-commit mode, the last nesting commit immediately starts a new transaction.
  1167
+                // Therefore we need to do the final commit here and then leave to avoid an infinite loop.
  1168
+                $this->commit();
  1169
+
  1170
+                return;
  1171
+            }
  1172
+
  1173
+            $this->commit();
  1174
+        }
1098 1175
     }
1099 1176
 
1100 1177
     /**
@@ -1125,6 +1202,10 @@ public function rollBack()
1125 1202
             if ($logger) {
1126 1203
                 $logger->stopQuery();
1127 1204
             }
  1205
+
  1206
+            if (false === $this->autoCommit) {
  1207
+                $this->beginTransaction();
  1208
+            }
1128 1209
         } else if ($this->_nestTransactionsWithSavepoints) {
1129 1210
             if ($logger) {
1130 1211
                 $logger->startQuery('"ROLLBACK TO SAVEPOINT"');
74  tests/Doctrine/Tests/DBAL/ConfigurationTest.php
... ...
@@ -0,0 +1,74 @@
  1
+<?php
  2
+/*
  3
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14
+ *
  15
+ * This software consists of voluntary contributions made by many individuals
  16
+ * and is licensed under the MIT license. For more information, see
  17
+ * <http://www.doctrine-project.org>.
  18
+ */
  19
+
  20
+namespace Doctrine\Tests\DBAL;
  21
+
  22
+use Doctrine\DBAL\Configuration;
  23
+use Doctrine\Tests\DbalTestCase;
  24
+
  25
+require_once __DIR__ . '/../TestInit.php';
  26
+
  27
+/**
  28
+ * Unit tests for the configuration container.
  29
+ *
  30
+ * @author Steve Müller <st.mueller@dzh-online.de>
  31
+ */
  32
+class ConfigurationTest extends DbalTestCase
  33
+{
  34
+    /**
  35
+     * The configuration container instance under test.
  36
+     *
  37
+     * @var \Doctrine\DBAL\Configuration
  38
+     */
  39
+    protected $config;
  40
+
  41
+    /**
  42
+     * {@inheritdoc}
  43
+     */
  44
+    public function setUp()
  45
+    {
  46
+        $this->config = new Configuration();
  47
+    }
  48
+
  49
+    /**
  50
+     * Tests that the default auto-commit mode for connections can be retrieved from the configuration container.
  51
+     *
  52
+     * @group DBAL-81
  53
+     */
  54
+    public function testReturnsDefaultConnectionAutoCommitMode()
  55
+    {
  56
+        $this->assertTrue($this->config->getAutoCommit());
  57
+    }
  58
+
  59
+    /**
  60
+     * Tests that the default auto-commit mode for connections can be set in the configuration container.
  61
+     *
  62
+     * @group DBAL-81
  63
+     */
  64
+    public function testSetsDefaultConnectionAutoCommitMode()
  65
+    {
  66
+        $this->config->setAutoCommit(false);
  67
+
  68
+        $this->assertFalse($this->config->getAutoCommit());
  69
+
  70
+        $this->config->setAutoCommit(0);
  71
+
  72
+        $this->assertFalse($this->config->getAutoCommit());
  73
+    }
  74
+}
101  tests/Doctrine/Tests/DBAL/ConnectionTest.php
@@ -8,6 +8,7 @@
8 8
 use Doctrine\Common\EventManager;
9 9
 use Doctrine\DBAL\Configuration;
10 10
 use Doctrine\DBAL\Events;
  11
+use Doctrine\Tests\Mocks\DriverConnectionMock;
11 12
 
12 13
 class ConnectionTest extends \Doctrine\Tests\DbalTestCase
13 14
 {
@@ -174,4 +175,104 @@ public function testDebugSQLStack()
174 175
         $this->_conn->getConfiguration()->setSQLLogger($logger);
175 176
         $this->assertSame($logger, $this->_conn->getConfiguration()->getSQLLogger());
176 177
     }
  178
+
  179
+    /**
  180
+     * @group DBAL-81
  181
+     */
  182
+    public function testIsAutoCommit()
  183
+    {
  184
+        $this->assertTrue($this->_conn->isAutoCommit());
  185
+    }
  186
+
  187
+    /**
  188
+     * @group DBAL-81
  189
+     */
  190
+    public function testSetAutoCommit()
  191
+    {
  192
+        $this->_conn->setAutoCommit(false);
  193
+        $this->assertFalse($this->_conn->isAutoCommit());
  194
+        $this->_conn->setAutoCommit(0);
  195
+        $this->assertFalse($this->_conn->isAutoCommit());
  196
+    }
  197
+
  198
+    /**
  199
+     * @group DBAL-81
  200
+     */
  201
+    public function testConnectStartsTransactionInNoAutoCommitMode()
  202
+    {
  203
+        $driverMock = $this->getMock('Doctrine\DBAL\Driver');
  204
+        $driverMock->expects($this->any())
  205
+            ->method('connect')
  206
+            ->will($this->returnValue(new DriverConnectionMock()));
  207
+        $conn = new Connection(array('platform' => new Mocks\MockPlatform()), $driverMock);
  208
+
  209
+        $conn->setAutoCommit(false);
  210
+
  211
+        $this->assertFalse($conn->isTransactionActive());
  212
+
  213
+        $conn->connect();
  214
+
  215
+        $this->assertTrue($conn->isTransactionActive());
  216
+    }
  217
+
  218
+    /**
  219
+     * @group DBAL-81
  220
+     */
  221
+    public function testCommitStartsTransactionInNoAutoCommitMode()
  222
+    {
  223
+        $driverMock = $this->getMock('Doctrine\DBAL\Driver');
  224
+        $driverMock->expects($this->any())
  225
+            ->method('connect')
  226
+            ->will($this->returnValue(new DriverConnectionMock()));
  227
+        $conn = new Connection(array('platform' => new Mocks\MockPlatform()), $driverMock);
  228
+
  229
+        $conn->setAutoCommit(false);
  230
+        $conn->connect();
  231
+        $conn->commit();
  232
+
  233
+        $this->assertTrue($conn->isTransactionActive());
  234
+    }
  235
+
  236
+    /**
  237
+     * @group DBAL-81
  238
+     */
  239
+    public function testRollBackStartsTransactionInNoAutoCommitMode()
  240
+    {
  241
+        $driverMock = $this->getMock('Doctrine\DBAL\Driver');
  242
+        $driverMock->expects($this->any())
  243
+            ->method('connect')
  244
+            ->will($this->returnValue(new DriverConnectionMock()));
  245
+        $conn = new Connection(array('platform' => new Mocks\MockPlatform()), $driverMock);
  246
+
  247
+        $conn->setAutoCommit(false);
  248
+        $conn->connect();
  249
+        $conn->rollBack();
  250
+
  251
+        $this->assertTrue($conn->isTransactionActive());
  252
+    }
  253
+
  254
+    /**
  255
+     * @group DBAL-81
  256
+     */
  257
+    public function testSwitchingAutoCommitModeCommitsAllCurrentTransactions()
  258
+    {
  259
+        $driverMock = $this->getMock('Doctrine\DBAL\Driver');
  260
+        $driverMock->expects($this->any())
  261
+            ->method('connect')
  262
+            ->will($this->returnValue(new DriverConnectionMock()));
  263
+        $conn = new Connection(array('platform' => new Mocks\MockPlatform()), $driverMock);
  264
+
  265
+        $conn->connect();
  266
+        $conn->beginTransaction();
  267
+        $conn->beginTransaction();
  268
+        $conn->setAutoCommit(false);
  269
+
  270
+        $this->assertSame(1, $conn->getTransactionNestingLevel());
  271
+
  272
+        $conn->beginTransaction();
  273
+        $conn->beginTransaction();
  274
+        $conn->setAutoCommit(true);
  275
+
  276
+        $this->assertFalse($conn->isTransactionActive());
  277
+    }
177 278
 }
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.