Browse Source

Revert #18102 since renaming is technically problematic (#18109)

tags/2.0.36
Alexander Makarov 4 years ago committed by GitHub
parent
commit
385fe13d66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 58
      docs/guide-es/db-dao.md
  2. 44
      docs/guide-fr/db-dao.md
  3. 32
      docs/guide-ja/db-dao.md
  4. 56
      docs/guide-ru/db-dao.md
  5. 54
      docs/guide-zh-CN/db-dao.md
  6. 114
      docs/guide/db-dao.md
  7. 14
      framework/CHANGELOG.md
  8. 2
      framework/db/Command.php
  9. 398
      framework/db/Connection.php
  10. 42
      framework/db/ConnectionDeprecationsTrait.php
  11. 2
      framework/db/mysql/Schema.php
  12. 2
      framework/db/oci/QueryBuilder.php
  13. 8
      framework/db/oci/Schema.php
  14. 6
      framework/db/pgsql/Schema.php
  15. 27
      framework/validators/ExistValidator.php
  16. 31
      framework/validators/UniqueValidator.php
  17. 6
      tests/framework/db/CommandTest.php
  18. 16
      tests/framework/db/ConnectionTest.php
  19. 6
      tests/framework/db/DatabaseTestCase.php
  20. 4
      tests/framework/db/SchemaTest.php
  21. 86
      tests/framework/db/sqlite/ConnectionTest.php
  22. 12
      tests/framework/helpers/VarDumperTest.php
  23. 10
      tests/framework/validators/ExistValidatorTest.php
  24. 16
      tests/framework/validators/UniqueValidatorTest.php

58
docs/guide-es/db-dao.md

@ -439,8 +439,8 @@ try {
Muchos DBMS soportan [replicación de bases de datos](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication) para tener
una mejor disponibilidad de la base de datos y un mejor tiempo de respuesta del servidor. Con la replicación de bases
de datos, los datos están replicados en los llamados *servidores maestros* (primary servers) y *servidores esclavos*
(replica servers). Todas las escrituras y actualizaciones deben hacerse en el servidor maestro, mientras que las lecturas
de datos, los datos están replicados en los llamados *servidores maestros* (master servers) y *servidores esclavos*
(slave servers). Todas las escrituras y actualizaciones deben hacerse en el servidor maestro, mientras que las lecturas
se efectuarán en los servidores esclavos.
Para aprovechar las ventajas de la replicación de la base de datos y lograr una división de lecuta-escritura, se puede configurar
@ -451,13 +451,13 @@ el componente [[yii\db\Connection]] como se muestra a continuación:
'class' => 'yii\db\Connection',
// configuración para el maestro
'dsn' => 'dsn for primary server',
'username' => 'primary',
'dsn' => 'dsn for master server',
'username' => 'master',
'password' => '',
// configuración para los esclavos
'replicaConfig' => [
'username' => 'replica',
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// utiliza un tiempo de espera de conexión más pequeña
@ -466,11 +466,11 @@ el componente [[yii\db\Connection]] como se muestra a continuación:
],
// listado de configuraciones de esclavos
'replicas' => [
['dsn' => 'dsn for replica server 1'],
['dsn' => 'dsn for replica server 2'],
['dsn' => 'dsn for replica server 3'],
['dsn' => 'dsn for replica server 4'],
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
@ -492,7 +492,7 @@ $db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
> Info: Las consultas realizadas llamando a [[yii\db\Command::execute()]] se consideran consultas de escritura,
mientras que todas las demás se ejecutan mediante alguno de los métodos "query" de [[yii\db\Command]] son consultas
de lectura. Se puede obtener la conexión de esclavo activa mediante `$db->replica`.
de lectura. Se puede obtener la conexión de esclavo activa mediante `$db->slave`.
El componente `Connection` soporta el balanceo de carga y la conmutación de errores entre esclavos. Cuando se realiza
una consulta de lectura por primera vez, el componente `Connection` elegirá un esclavo aleatorio e intentará realizar
@ -511,8 +511,8 @@ También se pueden configurar múltiples maestros con múltiples esclavos. Por e
'class' => 'yii\db\Connection',
// configuracion habitual para los maestros
'primaryConfig' => [
'username' => 'primary',
'masterConfig' => [
'username' => 'master',
'password' => '',
'attributes' => [
// utilizar un tiempo de espera de conexión más pequeña
@ -521,14 +521,14 @@ También se pueden configurar múltiples maestros con múltiples esclavos. Por e
],
// listado de configuraciones de maestros
'primaries' => [
['dsn' => 'dsn for primary server 1'],
['dsn' => 'dsn for primary server 2'],
'masters' => [
['dsn' => 'dsn for master server 1'],
['dsn' => 'dsn for master server 2'],
],
// configuración habitual para esclavos
'replicaConfig' => [
'username' => 'replica',
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// utilizar un tiempo de espera de conexión más pequeña
@ -537,11 +537,11 @@ También se pueden configurar múltiples maestros con múltiples esclavos. Por e
],
// listado de configuración de esclavos
'replicas' => [
['dsn' => 'dsn for replica server 1'],
['dsn' => 'dsn for replica server 2'],
['dsn' => 'dsn for replica server 3'],
['dsn' => 'dsn for replica server 4'],
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
@ -550,7 +550,7 @@ La configuración anterior especifica dos maestros y cuatro esclavos. El compone
balanceo de carga y la conmutación de errores entre maestros igual que hace con los esclavos. La diferencia es que
cuando no se encuentra ningún maestro disponible se lanza una excepción.
> Note: cuando se usa la propiedad [[yii\db\Connection::primaries|primaries]] para configurar uno o múltiples maestros, se
> Note: cuando se usa la propiedad [[yii\db\Connection::masters|masters]] para configurar uno o múltiples maestros, se
ignorarán todas las otras propiedades que especifiquen una conexión de base de datos
(ej. `dsn`, `username`, `password`), junto con el mismo objeto `Connection`.
@ -577,19 +577,19 @@ Si se quiere empezar la transacción con una conexión a un esclavo, se debe hac
continuación:
```php
$transaction = $db->replica->beginTransaction();
$transaction = $db->slave->beginTransaction();
```
A veces, se puede querer forzar el uso de una conexión maestra para realizar una consulta de lectura. Se puede lograr
usando el método `usePrimary()`:
usando el método `useMaster()`:
```php
$rows = $db->usePrimary(function ($db) {
$rows = $db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
```
También se puede utilizar directamente estableciendo `$db->enableReplicas` a `false` para que se redirijan todas las
También se puede utilizar directamente estableciendo `$db->enableSlaves` a `false` para que se redirijan todas las
consultas a la conexión del maestro.
## Trabajando con Esquemas de Bases de Datos <span id="database-schema"></span>

44
docs/guide-fr/db-dao.md

@ -425,12 +425,12 @@ Pour tirer parti de la réplication des bases de données et réaliser l'éclate
// configuration pour le maître
'dsn' => 'dsn pour le serveur maître',
'username' => 'primary',
'username' => 'master',
'password' => '',
// configuration commune pour les esclaves
'replicaConfig' => [
'username' => 'replica',
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// utilise un temps d'attente de connexion plus court
@ -439,7 +439,7 @@ Pour tirer parti de la réplication des bases de données et réaliser l'éclate
],
// liste des configurations d'esclave
'replicas' => [
'slaves' => [
['dsn' => 'dsn pour le serveur esclave 1'],
['dsn' => 'dsn pour le serveur esclave 2'],
['dsn' => 'dsn pour le serveur esclave 3'],
@ -461,7 +461,7 @@ $rows = Yii::$app->db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
```
> Info: les requêtes effectuées en appelant [[yii\db\Command::execute()]] sont considérées comme des requêtes en écriture, tandis que toutes les autres requêtes faites via l'une des méthodes « *query* » sont des requêtes en lecture. Vous pouvez obtenir la connexion couramment active à un des esclaves via `Yii::$app->db->replica`.
> Info: les requêtes effectuées en appelant [[yii\db\Command::execute()]] sont considérées comme des requêtes en écriture, tandis que toutes les autres requêtes faites via l'une des méthodes « *query* » sont des requêtes en lecture. Vous pouvez obtenir la connexion couramment active à un des esclaves via `Yii::$app->db->slave`.
Le composant `Connection` prend en charge l'équilibrage de charge et de basculement entre esclaves. Lorsque vous effectuez une requête en lecture par la première fois, le composant `Connection` sélectionne un esclave de façon aléatoire et essaye de s'y connecter. Si l'esclave set trouvé « mort », il en essaye un autre. Si aucun des esclaves n'est disponible, il se connecte au maître. En configurant un [[yii\db\Connection::serverStatusCache|cache d'état du serveur]], le composant mémorise le serveur « mort » et ainsi, pendant un [[yii\db\Connection::serverRetryInterval|certain intervalle de temps]], n'essaye plus de s'y connecter.
@ -476,8 +476,8 @@ Vous pouvez aussi configurer plusieurs maîtres avec plusieurs esclaves. Par exe
'class' => 'yii\db\Connection',
// configuration commune pour les maîtres
'primaryConfig' => [
'username' => 'primary',
'masterConfig' => [
'username' => 'master',
'password' => '',
'attributes' => [
// utilise un temps d'attente de connexion plus court
@ -486,14 +486,14 @@ Vous pouvez aussi configurer plusieurs maîtres avec plusieurs esclaves. Par exe
],
// liste des configurations de maître
'primaries' => [
['dsn' => 'dsn for primary server 1'],
['dsn' => 'dsn for primary server 2'],
'masters' => [
['dsn' => 'dsn for master server 1'],
['dsn' => 'dsn for master server 2'],
],
// configuration commune pour les esclaves
'replicaConfig' => [
'username' => 'replica',
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// use a smaller connection timeout
@ -502,18 +502,18 @@ Vous pouvez aussi configurer plusieurs maîtres avec plusieurs esclaves. Par exe
],
// liste des configurations d'esclave
'replicas' => [
['dsn' => 'dsn for replica server 1'],
['dsn' => 'dsn for replica server 2'],
['dsn' => 'dsn for replica server 3'],
['dsn' => 'dsn for replica server 4'],
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
La configuration ci-dessus spécifie deux maîtres et quatre esclaves. Le composant `Connection` prend aussi en charge l'équilibrage de charge et le basculement entre maîtres juste comme il le fait pour les esclaves. Une différence est que, si aucun des maîtres n'est disponible, une exception est levée.
> Note: lorsque vous utilisez la propriété [[yii\db\Connection::primaries|primaries]] pour configurer un ou plusieurs maîtres, toutes les autres propriétés pour spécifier une connexion à une base de données (p. ex. `dsn`, `username`, `password`) avec l'objet `Connection` lui-même sont ignorées.
> Note: lorsque vous utilisez la propriété [[yii\db\Connection::masters|masters]] pour configurer un ou plusieurs maîtres, toutes les autres propriétés pour spécifier une connexion à une base de données (p. ex. `dsn`, `username`, `password`) avec l'objet `Connection` lui-même sont ignorées.
Par défaut, les transactions utilisent la connexion au maître. De plus, dans une transaction, toutes les opérations de base de données utilisent la connexion au maître. Par exemple :
@ -538,18 +538,18 @@ try {
Si vous voulez démarrer une transaction avec une connexion à un esclave, vous devez le faire explicitement, comme ceci :
```php
$transaction = Yii::$app->db->replica->beginTransaction();
$transaction = Yii::$app->db->slave->beginTransaction();
```
Parfois, vous désirez forcer l'utilisation de la connexion au maître pour effectuer une requête en lecture . Cela est possible avec la méthode `usePrimary()` :
Parfois, vous désirez forcer l'utilisation de la connexion au maître pour effectuer une requête en lecture . Cela est possible avec la méthode `useMaster()` :
```php
$rows = Yii::$app->db->usePrimary(function ($db) {
$rows = Yii::$app->db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
```
Vous pouvez aussi définir directement `Yii::$app->db->enableReplicas` à `false` (faux) pour rediriger toutes les requêtes vers la connexion au maître.
Vous pouvez aussi définir directement `Yii::$app->db->enableSlaves` à `false` (faux) pour rediriger toutes les requêtes vers la connexion au maître.
## Travail avec le schéma de la base de données <span id="database-schema"></span>

32
docs/guide-ja/db-dao.md

@ -491,12 +491,12 @@ try {
// マスタの構成
'dsn' => 'マスタ・サーバの DSN',
'username' => 'primary',
'username' => 'master',
'password' => '',
// スレーブの共通の構成
'replicaConfig' => [
'username' => 'replica',
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// 短かめの接続タイムアウトを使う
@ -505,7 +505,7 @@ try {
],
// スレーブの構成のリスト
'replicas' => [
'slaves' => [
['dsn' => 'スレーブ・サーバ 1 の DSN'],
['dsn' => 'スレーブ・サーバ 2 の DSN'],
['dsn' => 'スレーブ・サーバ 3 の DSN'],
@ -531,7 +531,7 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
> Info: [[yii\db\Command::execute()]] を呼ぶことで実行されるクエリは、書き込みのクエリと見なされ、
[[yii\db\Command]] の "query" メソッドのうちの一つによって実行されるその他すべてのクエリは、読み出しクエリと見なされます。
現在アクティブなスレーブ接続は `Yii::$app->db->replica` によって取得することが出来ます。
現在アクティブなスレーブ接続は `Yii::$app->db->slave` によって取得することが出来ます。
`Connection` コンポーネントは、スレーブ間のロード・バランス調整とフェイルオーバーをサポートしています。
読み出しクエリを最初に実行するときに、`Connection` コンポーネントはランダムにスレーブを選んで接続を試みま・す。
@ -553,8 +553,8 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
'class' => 'yii\db\Connection',
// マスタの共通の構成
'primaryConfig' => [
'username' => 'primary',
'masterConfig' => [
'username' => 'master',
'password' => '',
'attributes' => [
// 短かめの接続タイムアウトを使う
@ -563,14 +563,14 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
],
// マスタの構成のリスト
'primaries' => [
'masters' => [
['dsn' => 'マスタ・サーバ 1 の DSN'],
['dsn' => 'マスタ・サーバ 2 の DSN'],
],
// スレーブの共通の構成
'replicaConfig' => [
'username' => 'replica',
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// 短かめの接続タイムアウトを使う
@ -579,7 +579,7 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
],
// スレーブの構成のリスト
'replicas' => [
'slaves' => [
['dsn' => 'スレーブ・サーバ 1 の DSN'],
['dsn' => 'スレーブ・サーバ 2 の DSN'],
['dsn' => 'スレーブ・サーバ 3 の DSN'],
@ -592,7 +592,7 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
`Connection` コンポーネントは、スレーブ間での場合と同じように、マスタ間でのロード・バランス調整とフェイルオーバーをサポートしています。
一つ違うのは、マスタが一つも利用できないときは例外が投げられる、という点です。
> Note: [[yii\db\Connection::primaries|primaries]] プロパティを使って一つまたは複数のマスタを構成する場合は、
> Note: [[yii\db\Connection::masters|masters]] プロパティを使って一つまたは複数のマスタを構成する場合は、
データベース接続を定義する `Connection` オブジェクト自体の他のプロパティ
(例えば、`dsn`、`username`、`password`) は全て無視されます。
@ -623,19 +623,19 @@ try {
スレーブ接続を使ってトランザクションを開始したいときは、次のように、明示的にそうする必要があります。
```php
$transaction = Yii::$app->db->replica->beginTransaction();
$transaction = Yii::$app->db->slave->beginTransaction();
```
時として、読み出しクエリの実行にマスタ接続を使うことを強制したい場合があります。
これは、`usePrimary()` メソッドを使うことによって達成できます。
これは、`useMaster()` メソッドを使うことによって達成できます。
```php
$rows = Yii::$app->db->usePrimary(function ($db) {
$rows = Yii::$app->db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
```
直接に `Yii::$app->db->enableReplicas``false` に設定して、全てのクエリをマスタ接続に向けることも出来ます。
直接に `Yii::$app->db->enableSlaves``false` に設定して、全てのクエリをマスタ接続に向けることも出来ます。
## データベース・スキーマを扱う <span id="database-schema"></span>

56
docs/guide-ru/db-dao.md

@ -437,7 +437,7 @@ try {
Многие СУБД поддерживают [репликацию баз данных](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication)
для лучшей доступности базы данных и уменьшения времени ответа сервера. С репликацией базы данных, данные копируются
из *primary servers* на *replica servers*. Все вставки и обновления должны происходить на основном сервере, хотя чтение
из *master servers* на *slave servers*. Все вставки и обновления должны происходить на основном сервере, хотя чтение
может производится и с подчинённых серверов.
Чтоб воспользоваться преимуществами репликации и достичь разделения чтения и записи, вам необходимо настроить компонент
@ -448,13 +448,13 @@ try {
'class' => 'yii\db\Connection',
// настройки для мастера
'dsn' => 'dsn for primary server',
'username' => 'primary',
'dsn' => 'dsn for master server',
'username' => 'master',
'password' => '',
// общие настройки для подчинённых
'replicaConfig' => [
'username' => 'replica',
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// используем небольшой таймаут для соединения
@ -463,11 +463,11 @@ try {
],
// список настроек для подчинённых серверов
'replicas' => [
['dsn' => 'dsn for replica server 1'],
['dsn' => 'dsn for replica server 2'],
['dsn' => 'dsn for replica server 3'],
['dsn' => 'dsn for replica server 4'],
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
@ -489,7 +489,7 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
> Info: Запросы выполненные через [[yii\db\Command::execute()]] определяются как запросы на запись, а все
остальные запросы через один из "query" методов [[yii\db\Command]] воспринимаются как запросы на чтение.
Вы можете получить текущий статус соединения к подчинённому серверу через `$db->replica`.
Вы можете получить текущий статус соединения к подчинённому серверу через `$db->slave`.
Компонент `Connection` поддерживает балансировку нагрузки и переключение при сбое для подчинённых серверов.
При выполнении первого запроса на чтение, компонент `Connection` будет случайным образом выбирать подчинённый сервер
@ -509,8 +509,8 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
'class' => 'yii\db\Connection',
// общая конфигурация для основных серверов
'primaryConfig' => [
'username' => 'primary',
'masterConfig' => [
'username' => 'master',
'password' => '',
'attributes' => [
// используем небольшой таймаут для соединения
@ -519,14 +519,14 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
],
// список настроек для основных серверов
'primaries' => [
['dsn' => 'dsn for primary server 1'],
['dsn' => 'dsn for primary server 2'],
'masters' => [
['dsn' => 'dsn for master server 1'],
['dsn' => 'dsn for master server 2'],
],
// общие настройки для подчинённых
'replicaConfig' => [
'username' => 'replica',
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// используем небольшой таймаут для соединения
@ -535,11 +535,11 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
],
// список настроек для подчинённых серверов
'replicas' => [
['dsn' => 'dsn for replica server 1'],
['dsn' => 'dsn for replica server 2'],
['dsn' => 'dsn for replica server 3'],
['dsn' => 'dsn for replica server 4'],
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
@ -548,7 +548,7 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
балансировку нагрузки и переключение при сбое между основными серверами, также как и между подчинёнными. Различие
заключается в том, что когда ни к одному из основных серверов не удастся подключиться будет выброшено исключение.
> Note: Когда вы используете свойство [[yii\db\Connection::primaries|primaries]] для настройки одного или нескольких
> Note: Когда вы используете свойство [[yii\db\Connection::masters|masters]] для настройки одного или нескольких
основных серверов, все остальные свойства для настройки соединения с базой данных (такие как `dsn`, `username`, `password`)
будут проигнорированы компонентом `Connection`.
@ -578,19 +578,19 @@ try {
Если вы хотите запустить транзакцию на подчинённом сервере, вы должны указать это явно, как показано ниже:
```php
$transaction = Yii::$app->db->replica->beginTransaction();
$transaction = Yii::$app->db->slave->beginTransaction();
```
Иногда может потребоваться выполнить запрос на чтение через подключение к основному серверу. Это может быть достигнуто
с использованием метода `usePrimary()`:
с использованием метода `useMaster()`:
```php
$rows = Yii::$app->db->usePrimary(function ($db) {
$rows = Yii::$app->db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
```
Вы также можете явно установить `$db->enableReplicas` в ложь, чтоб направлять все запросы к соединению с мастером.
Вы также можете явно установить `$db->enableSlaves` в ложь, чтоб направлять все запросы к соединению с мастером.
## Работа со схемой базы данных <span id="database-schema"></span>

54
docs/guide-zh-CN/db-dao.md

@ -484,13 +484,13 @@ try {
'class' => 'yii\db\Connection',
// 主库的配置
'dsn' => 'dsn for primary server',
'username' => 'primary',
'dsn' => 'dsn for master server',
'username' => 'master',
'password' => '',
// 从库的通用配置
'replicaConfig' => [
'username' => 'replica',
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// 使用一个更小的连接超时
@ -499,11 +499,11 @@ try {
],
// 从库的配置列表
'replicas' => [
['dsn' => 'dsn for replica server 1'],
['dsn' => 'dsn for replica server 2'],
['dsn' => 'dsn for replica server 3'],
['dsn' => 'dsn for replica server 4'],
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
@ -525,7 +525,7 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
> Info: 通过调用 [[yii\db\Command::execute()]] 来执行的语句都被视为写操作,
而其他所有通过调用 [[yii\db\Command]] 中任一 "query" 方法来执行的语句都被视为读操作。
你可以通过 `Yii::$app->db->replica` 来获取当前有效的从库连接。
你可以通过 `Yii::$app->db->slave` 来获取当前有效的从库连接。
`Connection` 组件支持从库间的负载均衡和失效备援,
当第一次执行读操作时,`Connection` 组件将随机地挑选出一个从库并尝试与之建立连接,
@ -547,8 +547,8 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
'class' => 'yii\db\Connection',
// 主库通用的配置
'primaryConfig' => [
'username' => 'primary',
'masterConfig' => [
'username' => 'master',
'password' => '',
'attributes' => [
// use a smaller connection timeout
@ -557,14 +557,14 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
],
// 主库配置列表
'primaries' => [
['dsn' => 'dsn for primary server 1'],
['dsn' => 'dsn for primary server 2'],
'masters' => [
['dsn' => 'dsn for master server 1'],
['dsn' => 'dsn for master server 2'],
],
// 从库的通用配置
'replicaConfig' => [
'username' => 'replica',
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// use a smaller connection timeout
@ -573,11 +573,11 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
],
// 从库配置列表
'replicas' => [
['dsn' => 'dsn for replica server 1'],
['dsn' => 'dsn for replica server 2'],
['dsn' => 'dsn for replica server 3'],
['dsn' => 'dsn for replica server 4'],
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
@ -586,7 +586,7 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
`Connection` 组件在主库之间,也支持如从库间般的负载均衡和失效备援。
唯一的差别是,如果没有主库可用,将抛出一个异常。
> Note: 当你使用 [[yii\db\Connection::primaries|primaries]] 属性来配置一个或多个主库时,
> Note: 当你使用 [[yii\db\Connection::masters|masters]] 属性来配置一个或多个主库时,
所有其他指定数据库连接的属性 (例如 `dsn`, `username`, `password`)
`Connection` 对象本身将被忽略。
@ -617,19 +617,19 @@ try {
如果你想在从库上开启事务,你应该明确地像下面这样做:
```php
$transaction = Yii::$app->db->replica->beginTransaction();
$transaction = Yii::$app->db->slave->beginTransaction();
```
有时,你或许想要强制使用主库来执行读查询。
这可以通过 `usePrimary()` 方法来完成:
这可以通过 `useMaster()` 方法来完成:
```php
$rows = Yii::$app->db->usePrimary(function ($db) {
$rows = Yii::$app->db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
```
你也可以明确地将 `Yii::$app->db->enableReplicas` 设置为 false 来将所有的读操作指向主库连接。
你也可以明确地将 `Yii::$app->db->enableSlaves` 设置为 false 来将所有的读操作指向主库连接。
## 操纵数据库模式(Working with Database Schema) <span id="database-schema"></span>

114
docs/guide/db-dao.md

@ -479,8 +479,8 @@ try {
Many DBMS support [database replication](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication)
to get better database availability and faster server response time. With database replication, data are replicated
from the so-called *primary servers* to *replica servers*. All writes and updates must take place on the primary servers,
while reads may also take place on the replica servers.
from the so-called *master servers* to *slave servers*. All writes and updates must take place on the master servers,
while reads may also take place on the slave servers.
To take advantage of database replication and achieve read-write splitting, you can configure a [[yii\db\Connection]]
component like the following:
@ -489,14 +489,14 @@ component like the following:
[
'class' => 'yii\db\Connection',
// configuration for the primary server
'dsn' => 'dsn for primary server',
'username' => 'primary',
// configuration for the master
'dsn' => 'dsn for master server',
'username' => 'master',
'password' => '',
// common configuration for replicas
'replicaConfig' => [
'username' => 'replica',
// common configuration for slaves
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// use a smaller connection timeout
@ -504,57 +504,57 @@ component like the following:
],
],
// list of replica configurations
'replicas' => [
['dsn' => 'dsn for replica server 1'],
['dsn' => 'dsn for replica server 2'],
['dsn' => 'dsn for replica server 3'],
['dsn' => 'dsn for replica server 4'],
// list of slave configurations
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
The above configuration specifies a setup with a single primary server and multiple replicas. One of the replicas
will be connected and used to perform read queries, while the primary server will be used to perform write queries.
The above configuration specifies a setup with a single master and multiple slaves. One of the slaves will
be connected and used to perform read queries, while the master will be used to perform write queries.
Such read-write splitting is accomplished automatically with this configuration. For example,
```php
// create a Connection instance using the above configuration
Yii::$app->db = Yii::createObject($config);
// query against one of the replicas
// query against one of the slaves
$rows = Yii::$app->db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
// query against the primary server
// query against the master
Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
```
> Info: Queries performed by calling [[yii\db\Command::execute()]] are considered as write queries, while
all other queries done through one of the "query" methods of [[yii\db\Command]] are read queries.
You can get the currently active replica connection via `Yii::$app->db->replica`.
You can get the currently active slave connection via `Yii::$app->db->slave`.
The `Connection` component supports load balancing and failover between replicas.
When performing a read query for the first time, the `Connection` component will randomly pick a replica and
try connecting to it. If the replica is found "dead", it will try another one. If none of the replicas are available,
it will connect to the primary server. By configuring a [[yii\db\Connection::serverStatusCache|server status cache]],
The `Connection` component supports load balancing and failover between slaves.
When performing a read query for the first time, the `Connection` component will randomly pick a slave and
try connecting to it. If the slave is found "dead", it will try another one. If none of the slaves is available,
it will connect to the master. By configuring a [[yii\db\Connection::serverStatusCache|server status cache]],
a "dead" server can be remembered so that it will not be tried again during a
[[yii\db\Connection::serverRetryInterval|certain period of time]].
> Info: In the above configuration, a connection timeout of 10 seconds is specified for every replica.
This means if a replica cannot be reached in 10 seconds, it is considered as "dead". You can adjust this parameter
> Info: In the above configuration, a connection timeout of 10 seconds is specified for every slave.
This means if a slave cannot be reached in 10 seconds, it is considered as "dead". You can adjust this parameter
based on your actual environment.
You can also configure multiple primary servers with multiple replicas. For example,
You can also configure multiple masters with multiple slaves. For example,
```php
[
'class' => 'yii\db\Connection',
// common configuration for primary servers
'primaryConfig' => [
'username' => 'primary',
// common configuration for masters
'masterConfig' => [
'username' => 'master',
'password' => '',
'attributes' => [
// use a smaller connection timeout
@ -562,15 +562,15 @@ You can also configure multiple primary servers with multiple replicas. For exam
],
],
// list of primary server configurations
'primaries' => [
['dsn' => 'dsn for primary server 1'],
['dsn' => 'dsn for primary server 2'],
// list of master configurations
'masters' => [
['dsn' => 'dsn for master server 1'],
['dsn' => 'dsn for master server 2'],
],
// common configuration for replicas
'replicaConfig' => [
'username' => 'replica',
// common configuration for slaves
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// use a smaller connection timeout
@ -578,35 +578,35 @@ You can also configure multiple primary servers with multiple replicas. For exam
],
],
// list of replica configurations
'replicas' => [
['dsn' => 'dsn for replica server 1'],
['dsn' => 'dsn for replica server 2'],
['dsn' => 'dsn for replica server 3'],
['dsn' => 'dsn for replica server 4'],
// list of slave configurations
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
The above configuration specifies two primary servers and four replicas. The `Connection` component also supports
load balancing and failover between primary servers just as it does between replicas. A difference is that when none
of the primary servers are available, an exception will be thrown.
The above configuration specifies two masters and four slaves. The `Connection` component also supports
load balancing and failover between masters just as it does between slaves. A difference is that when none
of the masters are available an exception will be thrown.
> Note: When you use the [[yii\db\Connection::primaries|primaries]] property to configure one or multiple
primary servers, all other properties for specifying a database connection (e.g. `dsn`, `username`, `password`)
> Note: When you use the [[yii\db\Connection::masters|masters]] property to configure one or multiple
masters, all other properties for specifying a database connection (e.g. `dsn`, `username`, `password`)
with the `Connection` object itself will be ignored.
By default, transactions use the primary connection. And within a transaction, all DB operations will use
the primary connection. For example,
By default, transactions use the master connection. And within a transaction, all DB operations will use
the master connection. For example,
```php
$db = Yii::$app->db;
// the transaction is started on the primary server
// the transaction is started on the master connection
$transaction = $db->beginTransaction();
try {
// both queries are performed against the primary server
// both queries are performed against the master
$rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
$db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
@ -620,22 +620,22 @@ try {
}
```
If you want to start a transaction with a replica, you should explicitly do so, like the following:
If you want to start a transaction with the slave connection, you should explicitly do so, like the following:
```php
$transaction = Yii::$app->db->replica->beginTransaction();
$transaction = Yii::$app->db->slave->beginTransaction();
```
Sometimes, you may want to force using the primary server to perform a read query. This can be achieved
with the `usePrimary()` method:
Sometimes, you may want to force using the master connection to perform a read query. This can be achieved
with the `useMaster()` method:
```php
$rows = Yii::$app->db->usePrimary(function ($db) {
$rows = Yii::$app->db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
```
You may also directly set `Yii::$app->db->enableReplicas` to be `false` to direct all queries to the primary server.
You may also directly set `Yii::$app->db->enableSlaves` to be `false` to direct all queries to the master connection.
## Working with Database Schema <span id="database-schema"></span>

14
framework/CHANGELOG.md

@ -17,20 +17,6 @@ Yii Framework 2 Change Log
- Bug #18001: Fix getting table metadata for tables `(` in their name (floor12)
- Bug #18096: Fix InlineValidator with anonymous inline function not working well from EachValidator (trombipeti)
- Enh #18083: Add `Controller::$request` and `$response` (brandonkelly)
- Enh #18102: Use “primary”/“replica” terminology instead of “master”/“slave” (brandonkelly)
- Added `yii\db\Connection::$enableReplicas` via magic methods and deprecated `$enableSlaves`.
- Added `yii\db\Connection::$replicas` via magic methods and deprecated `$slaves`.
- Added `yii\db\Connection::$replicaConfig` via magic methods and deprecated `$slaveConfig`.
- Added `yii\db\Connection::$primaries` via magic methods and deprecated `$masters`.
- Added `yii\db\Connection::$primaryConfig` via magic methods and deprecated `$masterConfig`.
- Added `yii\db\Connection::$shufflePrimaries` via magic methods and deprecated `$shuffleMasters`.
- Added `yii\db\Connection::getReplicaPdo()` and deprecated `getSlavePdo()`.
- Added `yii\db\Connection::getPrimaryPdo()` and deprecated `getMasterPdo()`.
- Added `yii\db\Connection::getReplica()` and deprecated `getSlave()`.
- Added `yii\db\Connection::getPrimary()` and deprecated `getMaster()`.
- Added `yii\db\Connection::usePrimary()` and deprecated `useMaster()`.
- Added `yii\validators\ExistValidator::$forcePrimaryDb` via magic methods and deprecated `$forceMasterDb`.
- Added `yii\validators\UniqueValidator::$forcePrimaryDb` via magic methods and deprecated `$forceMasterDb`.
- Bug #18101: Fix behavior of OUTPUT INSERTED.* for SQL Server query: "insert default values"; correct MSSQL unit tests; turn off profiling echo message in migration test (darkdef)
- Bug #18105: Fix for old trigger in RBAC migration with/without prefixTable (darkdef)

2
framework/db/Command.php

@ -248,7 +248,7 @@ class Command extends Component
$sql = $this->getSql();
if ($this->db->getTransaction()) {
// primary is in a transaction. use the same connection.
// master is in a transaction. use the same connection.
$forRead = false;
}
if ($forRead || $forRead === null && $this->db->getSchema()->isReadQuery($sql)) {

398
framework/db/Connection.php

@ -22,9 +22,9 @@ use yii\caching\CacheInterface;
* of the [PDO PHP extension](https://secure.php.net/manual/en/book.pdo.php).
*
* Connection supports database replication and read-write splitting. In particular, a Connection component
* can be configured with multiple [[primaries]] and [[replicas]]. It will do load balancing and failover by choosing
* appropriate servers. It will also automatically direct read operations to the replicas and write operations to
* the primary connections.
* can be configured with multiple [[masters]] and [[slaves]]. It will do load balancing and failover by choosing
* appropriate servers. It will also automatically direct read operations to the slaves and write operations to
* the masters.
*
* To establish a DB connection, set [[dsn]], [[username]] and [[password]], and then
* call [[open()]] to connect to the database server. The current state of the connection can be checked using [[$isActive]].
@ -114,55 +114,19 @@ use yii\caching\CacheInterface;
* @property bool $isActive Whether the DB connection is established. This property is read-only.
* @property string $lastInsertID The row ID of the last row inserted, or the last value retrieved from the
* sequence object. This property is read-only.
* @property bool $enableReplicas whether to enable read/write splitting by using [[replicas]] to read data.
* Note that if [[replicas]] is empty, read/write splitting will NOT be enabled no matter what value this property takes.
* @property array $replicas list of replica connection configurations. Each configuration is used to create a replica DB connection.
* When [[enableReplicas]] is true, one of these configurations will be chosen and used to create a DB connection
* for performing read queries only.
* @property array $replicaConfig the configuration that should be merged with every replica configuration listed in [[replicas]].
* For example,
*
* ```php
* [
* 'username' => 'replica',
* 'password' => 'replica',
* 'attributes' => [
* // use a smaller connection timeout
* PDO::ATTR_TIMEOUT => 10,
* ],
* ]
* ```
* @property array $primaries list of primary connection configurations. Each configuration is used to create a primary DB connection.
* When [[open()]] is called, one of these configurations will be chosen and used to create a DB connection
* which will be used by this object.
* Note that when this property is not empty, the connection setting (e.g. `dsn`, `username`) of this object will
* be ignored.
* @property array $primaryConfig the configuration that should be merged with every primary configuration listed in [[primaries]].
* For example,
*
* ```php
* [
* 'username' => 'primary',
* 'password' => 'primary',
* 'attributes' => [
* // use a smaller connection timeout
* PDO::ATTR_TIMEOUT => 10,
* ],
* ]
* ```
* @property bool $shufflePrimaries whether to shuffle [[primaries]] before getting one.
* @property-read Connection|null $primary The currently active primary connection. `null` is returned if no primary
* connection is available. This property is read-only.
* @property-read PDO $primaryPdo The PDO instance for the currently active primary connection. This property is
* @property Connection $master The currently active master connection. `null` is returned if there is no
* master available. This property is read-only.
* @property PDO $masterPdo The PDO instance for the currently active master connection. This property is
* read-only.
* @property QueryBuilder $queryBuilder The query builder for the current DB connection. Note that the type of
* this property differs in getter and setter. See [[getQueryBuilder()]] and [[setQueryBuilder()]] for details.
* @property Schema $schema The schema information for the database opened by this connection. This property
* is read-only.
* @property string $serverVersion Server version as a string. This property is read-only.
* @property-read Connection $replica The currently active replica connection. This property is read-only.
* @property-read PDO $replicaPdo The PDO instance for the currently active replica connection. This property
* is read-only.
* @property Connection $slave The currently active slave connection. `null` is returned if there is no slave
* available and `$fallbackToMaster` is false. This property is read-only.
* @property PDO $slavePdo The PDO instance for the currently active slave connection. `null` is returned if
* no slave connection is available and `$fallbackToMaster` is false. This property is read-only.
* @property Transaction|null $transaction The currently active transaction. Null if no active transaction.
* This property is read-only.
*
@ -365,208 +329,80 @@ class Connection extends Component
public $enableSavepoint = true;
/**
* @var CacheInterface|string|false the cache object or the ID of the cache application component that is used to store
* the health status of the DB servers specified in [[primaries]] and [[replicas]].
* This is used only when read/write splitting is enabled or [[primaries]] is not empty.
* the health status of the DB servers specified in [[masters]] and [[slaves]].
* This is used only when read/write splitting is enabled or [[masters]] is not empty.
* Set boolean `false` to disabled server status caching.
* @see openFromPoolSequentially() for details about the failover behavior.
* @see serverRetryInterval
*/
public $serverStatusCache = 'cache';
/**
* @var int the retry interval in seconds for dead servers listed in [[primaries]] and [[replicas]].
* @var int the retry interval in seconds for dead servers listed in [[masters]] and [[slaves]].
* This is used together with [[serverStatusCache]].
*/
public $serverRetryInterval = 600;
/**
* @var bool whether to enable read/write splitting by using [[replicas]] to read data.
* Note that if [[replicas]] is empty, read/write splitting will NOT be enabled no matter what value this property takes.
* @deprecated since 2.0.36. Use [[enableReplicas]] instead.
* @var bool whether to enable read/write splitting by using [[slaves]] to read data.
* Note that if [[slaves]] is empty, read/write splitting will NOT be enabled no matter what value this property takes.
*/
public $enableSlaves = true;
/**
* Returns the value of [[enableReplicas]].
* @return bool
* @since 2.0.36
* @internal
*/
public function getEnableReplicas()
{
return $this->enableSlaves;
}
/**
* Sets the value of [[enableReplicas]].
* @param bool $value
* @since 2.0.36
* @internal
*/
public function setEnableReplicas($value)
{
$this->enableSlaves = $value;
}
/**
* @var array list of replica connection configurations. Each configuration is used to create a replica DB connection.
* When [[enableReplicas]] is true, one of these configurations will be chosen and used to create a DB connection
* @var array list of slave connection configurations. Each configuration is used to create a slave DB connection.
* When [[enableSlaves]] is true, one of these configurations will be chosen and used to create a DB connection
* for performing read queries only.
* @see enableSlaves
* @see slaveConfig
* @deprecated since 2.0.36. Use [[replicas]] instead.
*/
public $slaves = [];
/**
* Returns the value of [[replicas]].
* @return array
* @since 2.0.36
* @internal
*/
public function getReplicas()
{
return $this->slaves;
}
/**
* Sets the value of [[replicas]].
* @param array $value
* @since 2.0.36
* @internal
*/
public function setReplicas($value)
{
$this->slaves = $value;
}
/**
* @var array the configuration that should be merged with every replica configuration listed in [[replicas]].
* @var array the configuration that should be merged with every slave configuration listed in [[slaves]].
* For example,
*
* ```php
* [
* 'username' => 'replica',
* 'password' => 'replica',
* 'username' => 'slave',
* 'password' => 'slave',
* 'attributes' => [
* // use a smaller connection timeout
* PDO::ATTR_TIMEOUT => 10,
* ],
* ]
* ```
*
* @deprecated since 2.0.36. Use [[replicaConfig]] instead.
*/
public $slaveConfig = [];
/**
* Returns the value of [[replicaConfig]].
* @return array
* @since 2.0.36
* @internal
*/
public function getReplicaConfig()
{
return $this->slaveConfig;
}
/**
* Sets the value of [[replicaConfig]].
* @param array $value
* @since 2.0.36
* @internal
*/
public function setReplicaConfig($value)
{
$this->slaveConfig = $value;
}
/**
* @var array list of primary connection configurations. Each configuration is used to create a primary DB connection.
* @var array list of master connection configurations. Each configuration is used to create a master DB connection.
* When [[open()]] is called, one of these configurations will be chosen and used to create a DB connection
* which will be used by this object.
* Note that when this property is not empty, the connection setting (e.g. `dsn`, `username`) of this object will
* Note that when this property is not empty, the connection setting (e.g. "dsn", "username") of this object will
* be ignored.
* @see masterConfig
* @see shuffleMasters
* @deprecated since 2.0.36. Use [[primaries]] instead.
*/
public $masters = [];
/**
* Returns the value of [[primaries]].
* @return array
* @since 2.0.36
* @internal
*/
public function getPrimaries()
{
return $this->masters;
}
/**
* Sets the value of [[primaries]].
* @param array $value
* @since 2.0.36
* @internal
*/
public function setPrimaries($value)
{
$this->masters = $value;
}
/**
* @var array the configuration that should be merged with every primary configuration listed in [[primaries]].
* @var array the configuration that should be merged with every master configuration listed in [[masters]].
* For example,
*
* ```php
* [
* 'username' => 'primary',
* 'password' => 'primary',
* 'username' => 'master',
* 'password' => 'master',
* 'attributes' => [
* // use a smaller connection timeout
* PDO::ATTR_TIMEOUT => 10,
* ],
* ]
* ```
*
* @deprecated since 2.0.36. Use [[primaryConfig]] instead.
*/
public $masterConfig = [];
/**
* Returns the value of [[primaryConfig]].
* @return array
* @since 2.0.36
* @internal
*/
public function getPrimaryConfig()
{
return $this->masterConfig;
}
/**
* Sets the value of [[primaryConfig]].
* @param array $value
* @since 2.0.36
* @internal
*/
public function setPrimaryConfig($value)
{
$this->masterConfig = $value;
}
/**
* @var bool whether to shuffle [[primaries]] before getting one.
* @var bool whether to shuffle [[masters]] before getting one.
* @since 2.0.11
* @see masters
* @deprecated since 2.0.36. Use [[shufflePrimaries]] instead.
*/
public $shuffleMasters = true;
/**
* Returns the value of [[shufflePrimaries]].
* @return bool
* @since 2.0.36
* @internal
*/
public function getShufflePrimaries()
{
return $this->shuffleMasters;
}
/**
* Sets the value of [[shufflePrimaries]].
* @param bool $value
* @since 2.0.36
* @internal
*/
public function setShufflePrimaries($value)
{
$this->shuffleMasters = $value;
}
/**
* @var bool whether to enable logging of database queries. Defaults to true.
* You may want to disable this option in a production environment to gain performance
* if you do not need the information being logged.
@ -596,13 +432,13 @@ class Connection extends Component
*/
private $_driverName;
/**
* @var Connection|false the currently active primary connection
* @var Connection|false the currently active master connection
*/
private $_primary = false;
private $_master = false;
/**
* @var Connection|false the currently active replica connection
* @var Connection|false the currently active slave connection
*/
private $_replica = false;
private $_slave = false;
/**
* @var array query cache parameters for the [[cache()]] calls
*/
@ -769,7 +605,7 @@ class Connection extends Component
return;
}
throw new InvalidConfigException('None of the primary DB servers are available.');
throw new InvalidConfigException('None of the master DB servers is available.');
}
if (empty($this->dsn)) {
@ -808,13 +644,13 @@ class Connection extends Component
*/
public function close()
{
if ($this->_primary) {
if ($this->pdo === $this->_primary->pdo) {
if ($this->_master) {
if ($this->pdo === $this->_master->pdo) {
$this->pdo = null;
}
$this->_primary->close();
$this->_primary = false;
$this->_master->close();
$this->_master = false;
}
if ($this->pdo !== null) {
@ -822,9 +658,9 @@ class Connection extends Component
$this->pdo = null;
}
if ($this->_replica) {
$this->_replica->close();
$this->_replica = false;
if ($this->_slave) {
$this->_slave->close();
$this->_slave = false;
}
$this->_schema = null;
@ -1162,139 +998,79 @@ class Connection extends Component
}
/**
* Returns the PDO instance for the currently active replica connection.
* When [[enableReplicas]] is true, one of the replicas will be used for read queries, and its PDO instance
* Returns the PDO instance for the currently active slave connection.
* When [[enableSlaves]] is true, one of the slaves will be used for read queries, and its PDO instance
* will be returned by this method.
* @param bool $fallbackToPrimary whether to return the primary PDO if no replica connections are available.
* @return PDO|null the PDO instance for the currently active replica connection. `null` is returned if no
* replica connections are available and `$fallbackToPrimary` is false.
* @since 2.0.36
* @param bool $fallbackToMaster whether to return a master PDO in case none of the slave connections is available.
* @return PDO the PDO instance for the currently active slave connection. `null` is returned if no slave connection
* is available and `$fallbackToMaster` is false.
*/
public function getReplicaPdo($fallbackToPrimary = true)
public function getSlavePdo($fallbackToMaster = true)
{
$db = $this->getSlave(false);
if ($db === null) {
return $fallbackToPrimary ? $this->getMasterPdo() : null;
return $fallbackToMaster ? $this->getMasterPdo() : null;
}
return $db->pdo;
}
/**
* Returns the PDO instance for the currently active replica connection.
* When [[enableReplicas]] is true, one of the replicas will be used for read queries, and its PDO instance
* will be returned by this method.
* @param bool $fallbackToPrimary whether to return the primary PDO if no replica connections are available.
* @return PDO|null the PDO instance for the currently active replica connection. `null` is returned if no
* replica connections are available and `$fallbackToPrimary` is false.
* @deprecated since 2.0.36. Use [[getReplicaPdo()]] instead.
* Returns the PDO instance for the currently active master connection.
* This method will open the master DB connection and then return [[pdo]].
* @return PDO the PDO instance for the currently active master connection.
*/
public function getSlavePdo($fallbackToPrimary = true)
{
return $this->getReplicaPdo($fallbackToPrimary);
}
/**
* Returns the PDO instance for the currently active primary connection.
* This method will open the primary DB connection and then return [[pdo]].
* @return PDO the PDO instance for the currently active primary connection.
* @since 2.0.36
*/
public function getPrimaryPdo()
public function getMasterPdo()
{
$this->open();
return $this->pdo;
}
/**
* Returns the PDO instance for the currently active primary connection.
* This method will open the primary DB connection and then return [[pdo]].
* @return PDO the PDO instance for the currently active primary connection.
* @deprecated since 2.0.36. Use [[getPrimaryPdo()]] instead.
* Returns the currently active slave connection.
* If this method is called for the first time, it will try to open a slave connection when [[enableSlaves]] is true.
* @param bool $fallbackToMaster whether to return a master connection in case there is no slave connection available.
* @return Connection the currently active slave connection. `null` is returned if there is no slave available and
* `$fallbackToMaster` is false.
*/
public function getMasterPdo()
{
return $this->getPrimaryPdo();
}
/**
* Returns the currently active replica connection.
* If this method is called for the first time, it will try to open a replica connection when [[enableReplicas]]
* is true.
* @param bool $fallbackToPrimary whether to return the primary connection if no replica connections are
* available.
* @return Connection|null the currently active replica connection. `null` is returned if no replica connections
* are available and `$fallbackToPrimary` is false.
* @since 2.0.36
*/
public function getReplica($fallbackToPrimary = true)
public function getSlave($fallbackToMaster = true)
{
if (!$this->enableSlaves) {
return $fallbackToPrimary ? $this : null;
return $fallbackToMaster ? $this : null;
}
if ($this->_replica === false) {
$this->_replica = $this->openFromPool($this->slaves, $this->slaveConfig);
if ($this->_slave === false) {
$this->_slave = $this->openFromPool($this->slaves, $this->slaveConfig);
}
return $this->_replica === null && $fallbackToPrimary ? $this : $this->_replica;
return $this->_slave === null && $fallbackToMaster ? $this : $this->_slave;
}
/**
* Returns the currently active replica connection.
* If this method is called for the first time, it will try to open a replica connection when [[enableReplicas]]
* is true.
* @param bool $fallbackToPrimary whether to return the primary connection if no replica connections are
* available.
* @return Connection|null the currently active replica connection. `null` is returned if no replica connections
* are available and `$fallbackToPrimary` is false.
* @deprecated since 2.0.36. Use [[getReplica()]] instead.
*/
public function getSlave($fallbackToPrimary = true)
{
return $this->getReplica($fallbackToPrimary);
}
/**
* Returns the currently active primary connection.
* If this method is called for the first time, it will try to open a primary connection.
* @return Connection|null the currently active primary connection. `null` is returned if no primary connection
* is available.
* @since 2.0.36
* Returns the currently active master connection.
* If this method is called for the first time, it will try to open a master connection.
* @return Connection the currently active master connection. `null` is returned if there is no master available.
* @since 2.0.11
*/
public function getPrimary()
public function getMaster()
{
if ($this->_primary === false) {
$this->_primary = $this->shuffleMasters
if ($this->_master === false) {
$this->_master = $this->shuffleMasters
? $this->openFromPool($this->masters, $this->masterConfig)
: $this->openFromPoolSequentially($this->masters, $this->masterConfig);
}
return $this->_primary;
return $this->_master;
}
/**
* Returns the currently active primary connection.
* If this method is called for the first time, it will try to open a primary connection.
* @return Connection|null the currently active primary connection. `null` is returned if no primary connection
* is available.
* @since 2.0.11
* @deprecated since 2.0.36. Use [[getPrimary()]] instead.
*/
public function getMaster()
{
return $this->getPrimary();
}
/**
* Executes the provided callback by using the primary connection.
* Executes the provided callback by using the master connection.
*
* This method is provided so that you can temporarily force using the primary connection to perform
* This method is provided so that you can temporarily force using the master connection to perform
* DB operations even if they are read queries. For example,
*
* ```php
* $result = $db->usePrimary(function ($db) {
* $result = $db->useMaster(function ($db) {
* return $db->createCommand('SELECT * FROM user LIMIT 1')->queryOne();
* });
* ```
@ -1303,9 +1079,8 @@ class Connection extends Component
* `function (Connection $db)`. Its return value will be returned by this method.
* @return mixed the return value of the callback
* @throws \Exception|\Throwable if there is any exception thrown from the callback
* @since 2.0.36
*/
public function usePrimary(callable $callback)
public function useMaster(callable $callback)
{
if ($this->enableSlaves) {
$this->enableSlaves = false;
@ -1328,29 +1103,6 @@ class Connection extends Component
}
/**
* Executes the provided callback by using the primary connection.
*
* This method is provided so that you can temporarily force using the primary connection to perform
* DB operations even if they are read queries. For example,
*
* ```php
* $result = $db->usePrimary(function ($db) {
* return $db->createCommand('SELECT * FROM user LIMIT 1')->queryOne();
* });
* ```
*
* @param callable $callback a PHP callable to be executed by this method. Its signature is
* `function (Connection $db)`. Its return value will be returned by this method.
* @return mixed the return value of the callback
* @throws \Exception|\Throwable if there is any exception thrown from the callback
* @deprecated since 2.0.36. Use [[usePrimary()]] instead.
*/
public function useMaster(callable $callback)
{
return $this->usePrimary($callback);
}
/**
* Opens the connection to a server in the pool.
*
* This method implements load balancing and failover among the given list of the servers.
@ -1467,8 +1219,8 @@ class Connection extends Component
$fields = (array) $this;
unset($fields['pdo']);
unset($fields["\000" . __CLASS__ . "\000" . '_primary']);
unset($fields["\000" . __CLASS__ . "\000" . '_replica']);
unset($fields["\000" . __CLASS__ . "\000" . '_master']);
unset($fields["\000" . __CLASS__ . "\000" . '_slave']);
unset($fields["\000" . __CLASS__ . "\000" . '_transaction']);
unset($fields["\000" . __CLASS__ . "\000" . '_schema']);
@ -1482,8 +1234,8 @@ class Connection extends Component
{
parent::__clone();
$this->_primary = false;
$this->_replica = false;
$this->_master = false;
$this->_slave = false;
$this->_schema = null;
$this->_transaction = null;
if (strncmp($this->dsn, 'sqlite::memory:', 15) !== 0) {

42
framework/db/ConnectionDeprecationsTrait.php

@ -1,42 +0,0 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db;
use PDO;
/**
* @internal This trait is only used to denote deprecated magic properties of [[Connection]] for IDEs via a
* `@mixin` tag. It is never actually loaded at runtime.
*
* @author Brandon Kelly <brandon@craftcms.com>
* @since 2.0.36
*/
trait ConnectionDeprecationsTrait
{
/**
* @var Connection|null The currently active primary connection. `null` is returned if no primary connection is
* available. This property is read-only.
* @deprecated since 2.0.36. Use [[Connection::$primary]] instead.
*/
public $master;
/**
* @var PDO The PDO instance for the currently active primary connection. This property is read-only.
* @deprecated since 2.0.36. Use [[Connection::$primaryPdo]] instead.
*/
public $masterPdo;
/**
* @var Connection The currently active replica connection. This property is read-only.
* @deprecated since 2.0.36. Use [[Connection::$replica]] instead.
*/
public $slave;
/**
* @var PDO The PDO instance for the currently active replica connection. This property is read-only.
* @deprecated since 2.0.36. Use [[Connection::$slavePdo]] instead.
*/
public $slavePdo;
}

2
framework/db/mysql/Schema.php

@ -327,7 +327,7 @@ SQL;
throw $e;
}
foreach ($columns as $info) {
if ($this->db->replicaPdo->getAttribute(\PDO::ATTR_CASE) !== \PDO::CASE_LOWER) {
if ($this->db->slavePdo->getAttribute(\PDO::ATTR_CASE) !== \PDO::CASE_LOWER) {
$info = array_change_key_case($info, CASE_LOWER);
}
$column = $this->loadColumnSchema($info);

2
framework/db/oci/QueryBuilder.php

@ -154,7 +154,7 @@ EOD;
if (count($tableSchema->primaryKey)>1) {
throw new InvalidArgumentException("Can't reset sequence for composite primary key in table: $table");
}
// use primary connection to get the biggest PK value
// use master connection to get the biggest PK value
$value = $this->db->useMaster(function (Connection $db) use ($tableSchema) {
return $db->createCommand(
'SELECT MAX("' . $tableSchema->primaryKey[0] . '") FROM "'. $tableSchema->name . '"'

8
framework/db/oci/Schema.php

@ -134,7 +134,7 @@ SQL;
$rows = $command->queryAll();
$names = [];
foreach ($rows as $row) {
if ($this->db->replicaPdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_LOWER) {
if ($this->db->slavePdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_LOWER) {
$row = array_change_key_case($row, CASE_UPPER);
}
$names[] = $row['TABLE_NAME'];
@ -337,7 +337,7 @@ SQL;
}
foreach ($columns as $column) {
if ($this->db->replicaPdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_LOWER) {
if ($this->db->slavePdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_LOWER) {
$column = array_change_key_case($column, CASE_UPPER);
}
$c = $this->createColumn($column);
@ -382,7 +382,7 @@ SQL;
public function getLastInsertID($sequenceName = '')
{
if ($this->db->isActive) {
// get the last insert id from the primary connection
// get the last insert id from the master connection
$sequenceName = $this->quoteSimpleTableName($sequenceName);
return $this->db->useMaster(function (Connection $db) use ($sequenceName) {
return $db->createCommand("SELECT {$sequenceName}.CURRVAL FROM DUAL")->queryScalar();
@ -467,7 +467,7 @@ SQL;
]);
$constraints = [];
foreach ($command->queryAll() as $row) {
if ($this->db->replicaPdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_LOWER) {
if ($this->db->slavePdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_LOWER) {
$row = array_change_key_case($row, CASE_UPPER);
}

6
framework/db/pgsql/Schema.php

@ -368,7 +368,7 @@ SQL;
$constraints = [];
foreach ($this->db->createCommand($sql)->queryAll() as $constraint) {
if ($this->db->replicaPdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_UPPER) {
if ($this->db->slavePdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_UPPER) {
$constraint = array_change_key_case($constraint, CASE_LOWER);
}
if ($constraint['foreign_table_schema'] !== $this->defaultSchema) {
@ -439,7 +439,7 @@ SQL;
$uniqueIndexes = [];
foreach ($this->getUniqueIndexInformation($table) as $row) {
if ($this->db->replicaPdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_UPPER) {
if ($this->db->slavePdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_UPPER) {
$row = array_change_key_case($row, CASE_LOWER);
}
$column = $row['columnname'];
@ -536,7 +536,7 @@ SQL;
return false;
}
foreach ($columns as $column) {
if ($this->db->replicaPdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_UPPER) {
if ($this->db->slavePdo->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_UPPER) {
$column = array_change_key_case($column, CASE_LOWER);
}
$column = $this->loadColumnSchema($column);

27
framework/validators/ExistValidator.php

@ -12,7 +12,6 @@ use yii\base\InvalidConfigException;
use yii\base\Model;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\db\Connection;
use yii\db\QueryInterface;
/**
@ -44,8 +43,6 @@ use yii\db\QueryInterface;
* ['type_id', 'exist', 'targetRelation' => 'type'],
* ```
*
* @property bool $forcePrimaryDb whether this validator is forced to always use the primary DB connection
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
@ -88,31 +85,10 @@ class ExistValidator extends Validator
*/
public $targetAttributeJunction = 'and';
/**
* @var bool whether this validator is forced to always use the primary DB connection
* @var bool whether this validator is forced to always use master DB
* @since 2.0.14
* @deprecated since 2.0.36. Use [[forcePrimaryDb]] instead.
*/
public $forceMasterDb = true;
/**
* Returns the value of [[forcePrimaryDb]].
* @return bool
* @since 2.0.36
* @internal
*/
public function getForcePrimaryDb()
{
return $this->forceMasterDb;
}
/**
* Sets the value of [[forcePrimaryDb]].
* @param bool $value
* @since 2.0.36
* @internal
*/
public function setForcePrimaryDb($value)
{
$this->forceMasterDb = $value;
}
/**
@ -279,7 +255,6 @@ class ExistValidator extends Validator
*/
private function valueExists($targetClass, $query, $value)
{
/** @var Connection|mixed $db */
$db = $targetClass::getDb();
$exists = false;

31
framework/validators/UniqueValidator.php

@ -13,7 +13,6 @@ use yii\db\ActiveQuery;
use yii\db\ActiveQueryInterface;
use yii\db\ActiveRecord;
use yii\db\ActiveRecordInterface;
use yii\db\Connection;
use yii\helpers\Inflector;
/**
@ -37,8 +36,6 @@ use yii\helpers\Inflector;
* ['a1', 'unique', 'targetAttribute' => ['a2', 'a1' => 'a3']]
* ```
*
* @property bool $forcePrimaryDb whether this validator is forced to always use the primary DB connection
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
@ -93,31 +90,10 @@ class UniqueValidator extends Validator
*/
public $targetAttributeJunction = 'and';
/**
* @var bool whether this validator is forced to always use the primary DB connection
* @var bool whether this validator is forced to always use master DB
* @since 2.0.14
* @deprecated since 2.0.36. Use [[forcePrimaryDb]] instead.
*/
public $forceMasterDb = true;
/**
* Returns the value of [[forcePrimaryDb]].
* @return bool
* @since 2.0.36
* @internal
*/
public function getForcePrimaryDb()
{
return $this->forceMasterDb;
}
/**
* Sets the value of [[forcePrimaryDb]].
* @param bool $value
* @since 2.0.36
* @internal
*/
public function setForcePrimaryDb($value)
{
$this->forceMasterDb = $value;
}
/**
@ -160,7 +136,6 @@ class UniqueValidator extends Validator
$conditions[] = [$key => $value];
}
/** @var Connection|mixed $db */
$db = $targetClass::getDb();
$modelExists = false;
@ -216,10 +191,10 @@ class UniqueValidator extends Validator
// only select primary key to optimize query
$columnsCondition = array_flip($targetClass::primaryKey());
$query->select(array_flip($this->applyTableAlias($query, $columnsCondition)));
// any with relation can't be loaded because related fields are not selected
$query->with = null;
if (is_array($query->joinWith)) {
// any joinWiths need to have eagerLoading turned off to prevent related fields being loaded
foreach ($query->joinWith as &$joinWith) {

6
tests/framework/db/CommandTest.php

@ -1296,7 +1296,7 @@ SQL;
public function testColumnCase()
{
$db = $this->getConnection(false);
$this->assertEquals(\PDO::CASE_NATURAL, $db->replicaPdo->getAttribute(\PDO::ATTR_CASE));
$this->assertEquals(\PDO::CASE_NATURAL, $db->slavePdo->getAttribute(\PDO::ATTR_CASE));
$sql = 'SELECT [[customer_id]], [[total]] FROM {{order}}';
$rows = $db->createCommand($sql)->queryAll();
@ -1304,13 +1304,13 @@ SQL;
$this->assertTrue(isset($rows[0]['customer_id']));
$this->assertTrue(isset($rows[0]['total']));
$db->replicaPdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER);
$db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER);
$rows = $db->createCommand($sql)->queryAll();
$this->assertTrue(isset($rows[0]));
$this->assertTrue(isset($rows[0]['customer_id']));
$this->assertTrue(isset($rows[0]['total']));
$db->replicaPdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_UPPER);
$db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_UPPER);
$rows = $db->createCommand($sql)->queryAll();
$this->assertTrue(isset($rows[0]));
$this->assertTrue(isset($rows[0]['CUSTOMER_ID']));

16
tests/framework/db/ConnectionTest.php

@ -409,7 +409,7 @@ abstract class ConnectionTest extends DatabaseTestCase
/**
* Test whether replica connection is recovered when getReplicaPdo() is called after close().
* Test whether slave connection is recovered when call getSlavePdo() after close().
*
* @see https://github.com/yiisoft/yii2/issues/14165
*/
@ -424,14 +424,14 @@ abstract class ConnectionTest extends DatabaseTestCase
$this->assertNotNull($connection->getSlavePdo(false));
$connection->close();
$primaryPdo = $connection->getMasterPdo();
$this->assertNotFalse($primaryPdo);
$this->assertNotNull($primaryPdo);
$masterPdo = $connection->getMasterPdo();
$this->assertNotFalse($masterPdo);
$this->assertNotNull($masterPdo);
$replicaPdo = $connection->getSlavePdo(false);
$this->assertNotFalse($replicaPdo);
$this->assertNotNull($replicaPdo);
$this->assertNotSame($primaryPdo, $replicaPdo);
$slavePdo = $connection->getSlavePdo(false);
$this->assertNotFalse($slavePdo);
$this->assertNotNull($slavePdo);
$this->assertNotSame($masterPdo, $slavePdo);
}
public function testServerStatusCacheWorks()

6
tests/framework/db/DatabaseTestCase.php

@ -130,15 +130,15 @@ abstract class DatabaseTestCase extends TestCase
return $sql;
}
}
/**
* @return \yii\db\Connection
*/
protected function getConnectionWithInvalidReplica()
protected function getConnectionWithInvalidSlave()
{
$config = array_merge($this->database, [
'serverStatusCache' => new DummyCache(),
'replicas' => [
'slaves' => [
[], // invalid config
],
]);

4
tests/framework/db/SchemaTest.php

@ -105,10 +105,10 @@ abstract class SchemaTest extends DatabaseTestCase
public function testGetTableSchemasWithAttrCase()
{
$db = $this->getConnection(false);
$db->replicaPdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER);
$db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER);
$this->assertEquals(\count($db->schema->getTableNames()), \count($db->schema->getTableSchemas()));
$db->replicaPdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_UPPER);
$db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_UPPER);
$this->assertEquals(\count($db->schema->getTableNames()), \count($db->schema->getTableSchemas()));
}

86
tests/framework/db/sqlite/ConnectionTest.php

@ -49,27 +49,27 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
$this->assertTrue(true); // No exceptions means test is passed.
}
public function testPrimaryReplica()
public function testMasterSlave()
{
$counts = [[0, 2], [1, 2], [2, 2]];
foreach ($counts as $count) {
list($primaryCount, $replicaCount) = $count;
list($masterCount, $slaveCount) = $count;
$db = $this->preparePrimaryReplica($primaryCount, $replicaCount);
$db = $this->prepareMasterSlave($masterCount, $slaveCount);
$this->assertInstanceOf(Connection::className(), $db->getSlave());
$this->assertTrue($db->getSlave()->isActive);
$this->assertFalse($db->isActive);
// test SELECT uses replica
// test SELECT uses slave
$this->assertEquals(2, $db->createCommand('SELECT COUNT(*) FROM profile')->queryScalar());
$this->assertFalse($db->isActive);
// test UPDATE uses primary
// test UPDATE uses master
$db->createCommand("UPDATE profile SET description='test' WHERE id=1")->execute();
$this->assertTrue($db->isActive);
if ($primaryCount > 0) {
if ($masterCount > 0) {
$this->assertInstanceOf(Connection::className(), $db->getMaster());
$this->assertTrue($db->getMaster()->isActive);
} else {
@ -82,7 +82,7 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
$this->assertEquals('test', $result);
// test ActiveRecord read/write split
ActiveRecord::$db = $db = $this->preparePrimaryReplica($primaryCount, $replicaCount);
ActiveRecord::$db = $db = $this->prepareMasterSlave($masterCount, $slaveCount);
$this->assertFalse($db->isActive);
$customer = Customer::findOne(1);
@ -103,60 +103,60 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
}
}
public function testPrimariesShuffled()
public function testMastersShuffled()
{
$primariesCount = 2;
$replicasCount = 2;
$mastersCount = 2;
$slavesCount = 2;
$retryPerNode = 10;
$nodesCount = $primariesCount + $replicasCount;
$nodesCount = $mastersCount + $slavesCount;
$hit_replicas = $hit_primaries = [];
$hit_slaves = $hit_masters = [];
for ($i = $nodesCount * $retryPerNode; $i-- > 0;) {
$db = $this->preparePrimaryReplica($primariesCount, $replicasCount);
$db = $this->prepareMasterSlave($mastersCount, $slavesCount);
$db->shuffleMasters = true;
$hit_replicas[$db->getSlave()->dsn] = true;
$hit_primaries[$db->getMaster()->dsn] = true;
if (\count($hit_replicas) === $replicasCount && \count($hit_primaries) === $primariesCount) {
$hit_slaves[$db->getSlave()->dsn] = true;
$hit_masters[$db->getMaster()->dsn] = true;
if (\count($hit_slaves) === $slavesCount && \count($hit_masters) === $mastersCount) {
break;
}
}
$this->assertCount($primariesCount, $hit_primaries, 'all primaries hit');
$this->assertCount($replicasCount, $hit_replicas, 'all replicas hit');
$this->assertCount($mastersCount, $hit_masters, 'all masters hit');
$this->assertCount($slavesCount, $hit_slaves, 'all slaves hit');
}
public function testPrimariesSequential()
public function testMastersSequential()
{
$primariesCount = 2;
$replicasCount = 2;
$mastersCount = 2;
$slavesCount = 2;
$retryPerNode = 10;
$nodesCount = $primariesCount + $replicasCount;
$nodesCount = $mastersCount + $slavesCount;
$hit_replicas = $hit_primaries = [];
$hit_slaves = $hit_masters = [];
for ($i = $nodesCount * $retryPerNode; $i-- > 0;) {
$db = $this->preparePrimaryReplica($primariesCount, $replicasCount);
$db = $this->prepareMasterSlave($mastersCount, $slavesCount);
$db->shuffleMasters = false;
$hit_replicas[$db->getSlave()->dsn] = true;
$hit_primaries[$db->getMaster()->dsn] = true;
if (\count($hit_replicas) === $replicasCount) {
$hit_slaves[$db->getSlave()->dsn] = true;
$hit_masters[$db->getMaster()->dsn] = true;
if (\count($hit_slaves) === $slavesCount) {
break;
}
}
$this->assertCount(1, $hit_primaries, 'same primary hit');
// replicas are always random
$this->assertCount($replicasCount, $hit_replicas, 'all replicas hit');
$this->assertCount(1, $hit_masters, 'same master hit');
// slaves are always random
$this->assertCount($slavesCount, $hit_slaves, 'all slaves hit');
}
public function testRestorePrimaryAfterException()
public function testRestoreMasterAfterException()
{
$db = $this->preparePrimaryReplica(1, 1);
$db = $this->prepareMasterSlave(1, 1);
$this->assertTrue($db->enableSlaves);
try {
$db->useMaster(function (Connection $db) {
@ -170,11 +170,11 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
}
/**
* @param int $primaryCount
* @param int $replicaCount
* @param int $masterCount
* @param int $slaveCount
* @return Connection
*/
protected function preparePrimaryReplica($primaryCount, $replicaCount)
protected function prepareMasterSlave($masterCount, $slaveCount)
{
$databases = self::getParam('databases');
$fixture = $databases[$this->driverName]['fixture'];
@ -186,18 +186,18 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
];
$this->prepareDatabase($config, $fixture)->close();
for ($i = 0; $i < $primaryCount; ++$i) {
$primary = ['dsn' => "sqlite:$basePath/yii2test_primary{$i}.sq3"];
$db = $this->prepareDatabase($primary, $fixture);
for ($i = 0; $i < $masterCount; ++$i) {
$master = ['dsn' => "sqlite:$basePath/yii2test_master{$i}.sq3"];
$db = $this->prepareDatabase($master, $fixture);
$db->close();
$config['primaries'][] = $primary;
$config['masters'][] = $master;
}
for ($i = 0; $i < $replicaCount; ++$i) {
$replica = ['dsn' => "sqlite:$basePath/yii2test_replica{$i}.sq3"];
$db = $this->prepareDatabase($replica, $fixture);
for ($i = 0; $i < $slaveCount; ++$i) {
$slave = ['dsn' => "sqlite:$basePath/yii2test_slave{$i}.sq3"];
$db = $this->prepareDatabase($slave, $fixture);
$db->close();
$config['replicas'][] = $replica;
$config['slaves'][] = $slave;
}
return \Yii::createObject($config);

12
tests/framework/helpers/VarDumperTest.php

@ -177,13 +177,13 @@ RESULT;
$exportResult = VarDumper::export($var);
$this->assertNotEmpty($exportResult);
$foo = new \StdClass();
$bar = new \StdClass();
$foo->bar = $bar;
$bar->foo = $foo;
$foo->function = function () {return true;};
$master = new \StdClass();
$slave = new \StdClass();
$master->slave = $slave;
$slave->master = $master;
$master->function = function () {return true;};
$exportResult = VarDumper::export($foo);
$exportResult = VarDumper::export($master);
$this->assertNotEmpty($exportResult);
}

10
tests/framework/validators/ExistValidatorTest.php

@ -235,10 +235,10 @@ abstract class ExistValidatorTest extends DatabaseTestCase
$val->validateAttribute($m, 'id');
$this->assertTrue($m->hasErrors('id'));
}
public function testForcePrimary()
public function testForceMaster()
{
$connection = $this->getConnectionWithInvalidReplica();
$connection = $this->getConnectionWithInvalidSlave();
ActiveRecord::$db = $connection;
$model = null;
@ -247,14 +247,14 @@ abstract class ExistValidatorTest extends DatabaseTestCase
});
$validator = new ExistValidator([
'forcePrimaryDb' => true,
'forceMasterDb' => true,
'targetRelation' => 'references',
]);
$validator->validateAttribute($model, 'id');
$this->expectException('\yii\base\InvalidConfigException');
$validator = new ExistValidator([
'forcePrimaryDb' => false,
'forceMasterDb' => false,
'targetRelation' => 'references',
]);
$validator->validateAttribute($model, 'id');

16
tests/framework/validators/UniqueValidatorTest.php

@ -445,7 +445,7 @@ abstract class UniqueValidatorTest extends DatabaseTestCase
$this->fail('Query is crashed because "with" relation cannot be loaded');
}
}
/**
* Test join with doesn't attempt to eager load joinWith relations
* @see https://github.com/yiisoft/yii2/issues/17389
@ -463,10 +463,10 @@ abstract class UniqueValidatorTest extends DatabaseTestCase
$this->fail('Query is crashed because "joinWith" relation cannot be loaded');
}
}
public function testForcePrimary()
public function testForceMaster()
{
$connection = $this->getConnectionWithInvalidReplica();
$connection = $this->getConnectionWithInvalidSlave();
ActiveRecord::$db = $connection;
$model = null;
@ -475,14 +475,14 @@ abstract class UniqueValidatorTest extends DatabaseTestCase
});
$validator = new UniqueValidator([
'forcePrimaryDb' => true,
'forceMasterDb' => true,
'targetAttribute' => ['status', 'profile_id']
]);
$validator->validateAttribute($model, 'email');
$this->expectException('\yii\base\InvalidConfigException');
$validator = new UniqueValidator([
'forcePrimaryDb' => false,
'forceMasterDb' => false,
'targetAttribute' => ['status', 'profile_id']
]);
$validator->validateAttribute($model, 'email');
@ -504,9 +504,9 @@ class WithCustomer extends Customer {
class JoinWithCustomer extends Customer {
public static function find() {
$res = parent::find();
$res->joinWith('profile');
return $res;
}
}

Loading…
Cancel
Save