Commit cc8a8360 by Carsten Brandt

added unit test and notes about dbms specific settings

parent e9996007
...@@ -323,10 +323,17 @@ You may use the constants named above but you can also use a string that represe ...@@ -323,10 +323,17 @@ You may use the constants named above but you can also use a string that represe
used in your DBMS following `SET TRANSACTION ISOLATION LEVEL`. For postgres this could be for example used in your DBMS following `SET TRANSACTION ISOLATION LEVEL`. For postgres this could be for example
`SERIALIZABLE READ ONLY DEFERRABLE`. `SERIALIZABLE READ ONLY DEFERRABLE`.
Note that some DBMS allow setting of the isolation level only for the whole connection so subsequent transactions
may get the same isolation level even if you did not specify any. When using this feature
you may need to set the isolation level for all transactions explicitly to avoid conflicting settings.
At the time of this writing affected DBMS are MSSQL and SQLite.
> Note: SQLite only supports two isolation levels, so you can only use `READ UNCOMMITTED` and `SERIALIZABLE`. > Note: SQLite only supports two isolation levels, so you can only use `READ UNCOMMITTED` and `SERIALIZABLE`.
Usage of other levels will result in an exception to be thrown. Usage of other levels will result in an exception to be thrown.
> Note: > Note: PostgreSQL does not allow settin the isolation level before the transaction starts so you can not
specify the isolation level directly when starting the transaction.
You have to call [[yii\db\Transaction::setIsolationLevel()]] in this case after the transaction has started.
[isolation levels]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels [isolation levels]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
......
...@@ -86,6 +86,14 @@ class Transaction extends \yii\base\Object ...@@ -86,6 +86,14 @@ class Transaction extends \yii\base\Object
* also a string containing DBMS specific syntax to be used after `SET TRANSACTION ISOLATION LEVEL`. * also a string containing DBMS specific syntax to be used after `SET TRANSACTION ISOLATION LEVEL`.
* If not specified (`null`) the isolation level will not be set explicitly and the DBMS default will be used. * If not specified (`null`) the isolation level will not be set explicitly and the DBMS default will be used.
* *
* > Note: This setting does not work for PostgreSQL, where setting the isolation level before the transaction
* has no effect. You have to call [[setIsolationLevel()]] in this case after the transaction has started.
*
* > Note: Some DBMS allow setting of the isolation level only for the whole connection so subsequent transactions
* may get the same isolation level even if you did not specify any. When using this feature
* you may need to set the isolation level for all transactions explicitly to avoid conflicting settings.
* At the time of this writing affected DBMS are MSSQL and SQLite.
*
* [isolation level]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels * [isolation level]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
* @throws InvalidConfigException if [[db]] is `null`. * @throws InvalidConfigException if [[db]] is `null`.
*/ */
......
...@@ -10,6 +10,7 @@ namespace yii\db\cubrid; ...@@ -10,6 +10,7 @@ namespace yii\db\cubrid;
use yii\db\Expression; use yii\db\Expression;
use yii\db\TableSchema; use yii\db\TableSchema;
use yii\db\ColumnSchema; use yii\db\ColumnSchema;
use yii\db\Transaction;
/** /**
* Schema is the class for retrieving metadata from a CUBRID database (version 9.1.x and higher). * Schema is the class for retrieving metadata from a CUBRID database (version 9.1.x and higher).
...@@ -284,4 +285,28 @@ class Schema extends \yii\db\Schema ...@@ -284,4 +285,28 @@ class Schema extends \yii\db\Schema
return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR;
} }
/**
* @inheritdoc
* @see http://www.cubrid.org/manual/91/en/sql/transaction.html#database-concurrency
*/
public function setTransactionIsolationLevel($level)
{
// translate SQL92 levels to CUBRID levels:
switch ($level) {
case Transaction::SERIALIZABLE:
$level = '6'; // SERIALIZABLE
break;
case Transaction::REPEATABLE_READ:
$level = '5'; // REPEATABLE READ CLASS with REPEATABLE READ INSTANCES
break;
case Transaction::READ_COMMITTED:
$level = '4'; // REPEATABLE READ CLASS with READ COMMITTED INSTANCES
break;
case Transaction::READ_UNCOMMITTED:
$level = '3'; // REPEATABLE READ CLASS with READ UNCOMMITTED INSTANCES
break;
}
return parent::setTransactionIsolationLevel($level);
}
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace yiiunit\framework\db; namespace yiiunit\framework\db;
use yii\db\Connection; use yii\db\Connection;
use yii\db\Transaction;
/** /**
* @group db * @group db
...@@ -77,4 +78,47 @@ class ConnectionTest extends DatabaseTestCase ...@@ -77,4 +78,47 @@ class ConnectionTest extends DatabaseTestCase
$this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}'));
$this->assertEquals('(column)', $connection->quoteColumnName('(column)')); $this->assertEquals('(column)', $connection->quoteColumnName('(column)'));
} }
public function testTransaction()
{
$connection = $this->getConnection(false);
$this->assertNull($connection->transaction);
$transaction = $connection->beginTransaction();
$this->assertNotNull($connection->transaction);
$this->assertTrue($transaction->isActive);
$connection->createCommand()->insert('profile', ['description' => 'test transaction'])->execute();
$transaction->rollBack();
$this->assertFalse($transaction->isActive);
$this->assertNull($connection->transaction);
$this->assertEquals(0, $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction';")->queryScalar());
$transaction = $connection->beginTransaction();
$connection->createCommand()->insert('profile', ['description' => 'test transaction'])->execute();
$transaction->commit();
$this->assertFalse($transaction->isActive);
$this->assertNull($connection->transaction);
$this->assertEquals(1, $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction';")->queryScalar());
}
public function testTransactionIsolation()
{
$connection = $this->getConnection(true);
$transaction = $connection->beginTransaction(Transaction::READ_UNCOMMITTED);
$transaction->commit();
$transaction = $connection->beginTransaction(Transaction::READ_COMMITTED);
$transaction->commit();
$transaction = $connection->beginTransaction(Transaction::REPEATABLE_READ);
$transaction->commit();
$transaction = $connection->beginTransaction(Transaction::SERIALIZABLE);
$transaction->commit();
}
} }
<?php <?php
namespace yiiunit\framework\db\sqlite; namespace yiiunit\framework\db\sqlite;
use yii\db\Transaction;
use yiiunit\framework\db\ConnectionTest; use yiiunit\framework\db\ConnectionTest;
/** /**
...@@ -45,4 +46,15 @@ class SqliteConnectionTest extends ConnectionTest ...@@ -45,4 +46,15 @@ class SqliteConnectionTest extends ConnectionTest
$this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}'));
$this->assertEquals('(column)', $connection->quoteColumnName('(column)')); $this->assertEquals('(column)', $connection->quoteColumnName('(column)'));
} }
public function testTransactionIsolation()
{
$connection = $this->getConnection(true);
$transaction = $connection->beginTransaction(Transaction::READ_UNCOMMITTED);
$transaction->rollBack();
$transaction = $connection->beginTransaction(Transaction::SERIALIZABLE);
$transaction->rollBack();
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment