Commit 0f5051b3 by pana1990 Committed by Carsten Brandt

Update db-dao in guide-es [skip ci]

close #7143
parent 3632d041
Objetos de Acceso a Bases de Datos Objetos de Acceso a Bases de Datos
================================== ==================================
> Nota: Esta sección está en desarrollo. Construido sobre [PDO](http://php.net/manual/es/book.pdo.php), Yii DAO (Objetos de Acceso a Bases de Datos) proporciona una
API orientada a objetos para el acceso a bases de datos relacionales. Es el fundamento para otros métodos de acceso a bases de datos
más avanzados, incluyendo el [constructor de consultas](db-query-builder.md) y [active record](db-active-record.md).
Yii incluye una capa de acceso a bases de datos basado en el [PDO](http://php.net/manual/es/book.pdo.php) de PHP. La Al utilizar Yii DAO, principalmente vas a tratar con SQLs planos y arrays PHP. Como resultado, esta es la manera más eficiente
interfaz de objetos de acceso a bases de datos (DAO) proporciona una API uniforme y soluciona algunas inconsistencias de acceder a las bases de datos. Sin embargo, como la sintaxis puede variar para las diferentes bases de datos, utilizando
que existen entre diferentes aplicaciones de bases de datos. Mientras el Active Record proporciona interacciones con Yii DAO también significa que tienes que tienes que tomar un esfuerzo adicional para crear una aplicación de database-agnostic.
los modelos, y el Constructor de Consultas (Query Builder) ayuda en la composición de consultas dinámicas, DAO es una
manera simple y eficiente para ejecutar SQL en la base de datos. Por lo general, se usará DAO cuando la ejecución de
la consulta sea muy costosa y/o no se requieran modelos de aplicación y sus correspondientes lógicas de negocio.
De forma predeterminada, Yii soporta los siguientes DBMS (Sistemas de Gestión de Base de Datos): Yii DAO soporta las siguientes bases de datos:
- [MySQL](http://www.mysql.com/) - [MySQL](http://www.mysql.com/)
- [MariaDB](https://mariadb.com/) - [MariaDB](https://mariadb.com/)
- [SQLite](http://sqlite.org/) - [SQLite](http://sqlite.org/)
- [PostgreSQL](http://www.postgresql.org/) - [PostgreSQL](http://www.postgresql.org/)
- [CUBRID](http://www.cubrid.org/): versión 9.3 o superior. (Tenga en cuenta que debido al - [CUBRID](http://www.cubrid.org/): versión 9.3 o superior.
[bug](http://jira.cubrid.org/browse/APIS-658) en la extensión PDO de cubrid, los valores entrecomillados no
funcionarán, por lo que se necesita CUBRID 9.3 tanto para el cliente como para el servidor)
- [Oracle](http://www.oracle.com/us/products/database/overview/index.html) - [Oracle](http://www.oracle.com/us/products/database/overview/index.html)
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): versión 2008 o superior. - [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): versión 2008 o superior.
Configuración ## Creando Conexiones DB <span id="creating-db-connections"></span>
-------------
Para empezar a interaccionar con la base de datos (usando DAO o de otra forma), se tiene que configurar el componente Para acceder a una base de datos, primero necesitas conectarte a tu bases de datos mediante la creación
de conexión a la base de datos de la aplicación. El DSN (Nombre de Origen de Datos) configura que aplicación de BBDD y de una instancia de [yii\db\Connection]]:
que BBDD especifica debe conectar la aplicación:
```php
$db = new yii\db\Connection([
'dsn' => 'mysql:host=localhost;dbname=example',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
```
Debido a una conexión DB a menudo necesita ser accedido en diferentes lugares, una práctica común es
configurarlo en términos de un [componente de aplicación](structure-application-components.md) como
se muestra a continuación:
```php ```php
return [ return [
...@@ -36,14 +44,7 @@ return [ ...@@ -36,14 +44,7 @@ return [
// ... // ...
'db' => [ 'db' => [
'class' => 'yii\db\Connection', 'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=mydatabase', // MySQL, MariaDB 'dsn' => 'mysql:host=localhost;dbname=example',
//'dsn' => 'sqlite:/path/to/database/file', // SQLite
//'dsn' => 'pgsql:host=localhost;port=5432;dbname=mydatabase', // PostgreSQL
//'dsn' => 'cubrid:dbname=demodb;host=localhost;port=33000', // CUBRID
//'dsn' => 'sqlsrv:Server=localhost;Database=mydatabase', // MS SQL Server, sqlsrv driver
//'dsn' => 'dblib:host=localhost;dbname=mydatabase', // MS SQL Server, dblib driver
//'dsn' => 'mssql:host=localhost;dbname=mydatabase', // MS SQL Server, mssql driver
//'dsn' => 'oci:dbname=//localhost:1521/mydatabase', // Oracle
'username' => 'root', 'username' => 'root',
'password' => '', 'password' => '',
'charset' => 'utf8', 'charset' => 'utf8',
...@@ -53,12 +54,25 @@ return [ ...@@ -53,12 +54,25 @@ return [
]; ];
``` ```
Se puede encontrar más información del formato de la cadena DSN en el Puedes acceder a la conexión DB mediante la expresión `Yii::$app->db`.
[manual de PHP](http://php.net/manual/es/pdo.construct.php). Además se puede encontrar el listado completo de
propiedades que se pueden configurar en la clase en [[yii\db\Connection]]. > Consejo: Puedes configurar múltiples componentes de aplicación DB si tu aplicación necesita acceder a múltiples bases de datos.
Hay que tener en cuenta que si se conecta a una base de datos mediante ODBC, se debe configurar la propiedad Cuando configuras una conexión DB, deberías siempre especificar el Nombre de Origen de Datos (DSN) mediante la
[[yii\db\Connection::driverName]] para que Yii sepa el tipo de bases de datos actual. Por ejemplo, propiedad [[yii\db\Connection::dsn|dsn]]. El formato del DSN varia para cada diferente base de datos. Por favor consulte el
[manual de PHP](http://www.php.net/manual/es/function.PDO-construct.php) para más detalles. Abajo están algunos ejemplos:
* MySQL, MariaDB: `mysql:host=localhost;dbname=mydatabase`
* SQLite: `sqlite:/path/to/database/file`
* PostgreSQL: `pgsql:host=localhost;port=5432;dbname=mydatabase`
* CUBRID: `cubrid:dbname=demodb;host=localhost;port=33000`
* MS SQL Server (mediante sqlsrv driver): `sqlsrv:Server=localhost;Database=mydatabase`
* MS SQL Server (mediante dblib driver): `dblib:host=localhost;dbname=mydatabase`
* MS SQL Server (mediante mssql driver): `mssql:host=localhost;dbname=mydatabase`
* Oracle: `oci:dbname=//localhost:1521/mydatabase`
Nota que si estás conectándote con una base de datos mediante ODBC, deberías configurar la propiedad [[yii\db\Connection::driverName]]
para que Yii pueda conocer el tipo de base de datos actual. Por ejemplo,
```php ```php
'db' => [ 'db' => [
...@@ -70,53 +84,53 @@ Hay que tener en cuenta que si se conecta a una base de datos mediante ODBC, se ...@@ -70,53 +84,53 @@ Hay que tener en cuenta que si se conecta a una base de datos mediante ODBC, se
], ],
``` ```
Se puede acceder a la conexión `db` primaria mediante la expresión `\Yii::$app->db`. También se pueden configurar Además de la propiedad [[yii\db\Connection::dsn|dsn]], a menudo es necesario configurar el [[yii\db\Connection::username|username]]
múltiples conexiones de BBDD en una única aplicación. Simplemente asignándoles diferentes IDs en la configuración de y [[yii\db\Connection::password|password]]. Por favor consulta [[yii\db\Connection]] para ver la lista completa de propiedades configurables.
la aplicación:
```php > Información: Cuando se crea una instancia de conexión DB, la conexión actual a la base de datos no se establece hasta que
return [ ejecutes el primer SQL o llames explícitamente al método [[yii\db\Connection::open()|open()]].
// ...
'components' => [
// ...
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=mydatabase',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
'secondDb' => [
'class' => 'yii\db\Connection',
'dsn' => 'sqlite:/path/to/database/file',
],
],
// ...
];
```
Ahora se pueden usar las dos conexiones a la base de datos al mismo tiempo si es necesario:
```php ## Ejecutando Consultas SQL <span id="executing-sql-queries"></span>
$primaryConnection = \Yii::$app->db;
$secondaryConnection = \Yii::$app->secondDb; Una vez tienes instanciada una conexión a la base de datos, se pueden ejecutar consultas SQL tomando
``` los siguientes pasos:
1. Crea un [[yii\db\Command]] con SQL plano;
2. Vincula parámetros (opcional);
3. Llama a uno de los métodos de ejecución SQL con [[yii\db\Command]].
Si no se quiere definir la conexión como un [componente de aplicación](structure-application-components.md), se puede El siguiente ejemplo muestra varias maneras de obtener datos de una base de datos:
instanciar directamente:
```php ```php
$connection = new \yii\db\Connection([ $db = new yii\db\Connection(...);
'dsn' => $dsn,
'username' => $username, // retorna un conjunto de filas. Cada fila es un array asociativo de columnas de nombres y valores.
'password' => $password, // un array vacío es retornado si no hay resultados
]); $posts = $db->createCommand('SELECT * FROM post')
$connection->open(); ->queryAll();
// retorna una sola fila (la primera fila)
// false es retornado si no hay resultados
$post = $db->createCommand('SELECT * FROM post WHERE id=1')
->queryOne();
// retorna una sola columna (la primera columna)
// un array vacío es retornado si no hay resultados
$titles = $db->createCommand('SELECT title FROM post')
->queryColumn();
// retorna un escalar
// false es retornado si no hay resultados
$count = $db->createCommand('SELECT COUNT(*) FROM post')
->queryScalar();
``` ```
> Consejo: Si se necesita ejecutar una consulta SQL inmediatamente después de establecer la conexión > Nota: Para preservar la precisión, los datos obtenidos de las bases de datos son todos representados como cadenas, incluso si el tipo de columna correspondiente
(ej. para establecer la zona horaria (timezone) o el juego de caracteres), se puede añadir el siguiente código en el a la base de datos es numérico.
archivo de configuración de la aplicación:
> Consejo: Si necesitas ejecutar una consulta SQL inmediatamente después de establecer una conexión (ej., para establecer una zona horaria o un conjunto de caracteres),
> puedes hacerlo con el evento [[yii\db\Connection::EVENT_AFTER_OPEN]]. Por ejemplo,
> >
```php ```php
return [ return [
...@@ -127,6 +141,7 @@ return [ ...@@ -127,6 +141,7 @@ return [
'class' => 'yii\db\Connection', 'class' => 'yii\db\Connection',
// ... // ...
'on afterOpen' => function($event) { 'on afterOpen' => function($event) {
// $event->sender se refiere a la conexión DB
$event->sender->createCommand("SET time_zone = 'UTC'")->execute(); $event->sender->createCommand("SET time_zone = 'UTC'")->execute();
} }
], ],
...@@ -135,101 +150,141 @@ return [ ...@@ -135,101 +150,141 @@ return [
]; ];
``` ```
Ejecución de Consultas SQL Básicas
----------------------------------
Una vez instanciada una conexión a la base de datos, se pueden ejecutar consultas SQL usando [[yii\db\Command]]. ### Parámetros Vinculados (Binding Parameters) <span id="binding-parameters"></span>
### Ejecutando Consultas SELECT Cuando creamos un comando DB para un SQL con parámetros, nosotros deberíamos casi siempre aprovechar el uso de los parámetros vinculados
para prevenir los ataques de inyección de SQL. Por ejemplo,
Cuando la consulta que tiene que ser ejecutada devuelve un conjunto de filas, se usará `queryAll`:
```php ```php
$command = $connection->createCommand('SELECT * FROM post'); $post = $db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status')
$posts = $command->queryAll(); ->bindValue(':id', $_GET['id'])
->bindValue(':status', 1)
->queryOne();
``` ```
Cuando la consulta que se ejecute devuelva una única fila, se usará `queryOne`: En la sentencia SQL, puedes incrustar uno o múltiples parámetros placeholders (ej. `:id` en el ejemplo anterior). Un parámetro
placeholder debería ser una cadena que empiece con dos puntos. A continuación puedes llamar a uno de los siguientes métodos para
unir los valores de los parámetros vinculados:
* [[yii\db\Command::bindValue()|bindValue()]]: une un solo parámetro
* [[yii\db\Command::bindValues()|bindValues()]]: une múltiples parámetros en una sola llamada
* [[yii\db\Command::bindParam()|bindParam()]]: similar a [[yii\db\Command::bindValue()|bindValue()]] pero también
soporta las referencias de parámetros vinculados.
El siguiente ejemplo muestra formas alternativas de vincular parámetros:
```php ```php
$command = $connection->createCommand('SELECT * FROM post WHERE id=1'); $params = [':id' => $_GET['id'], ':status' => 1];
$post = $command->queryOne();
$post = $db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status')
->bindValues($params)
->queryOne();
$post = $db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status', $params)
->queryOne();
``` ```
Cuando la consulta devuelva múltiples filas pero solo una columna, se usará `queryColumn`: La vinculación parámetros es implementada mediante [sentencias preparadas (prepared statements)](http://php.net/manual/es/mysqli.quickstart.prepared-statements.php).
Además de prevenir ataques de inyección de SQL, también puede mejorar el rendimiento preparando una sola vez una sentencia SQL y ejecutándola múltiples veces con diferentes
parámetros. Por ejemplo,
```php ```php
$command = $connection->createCommand('SELECT title FROM post'); $command = $db->createCommand('SELECT * FROM post WHERE id=:id');
$titles = $command->queryColumn();
$post1 = $command->bindValue(':id', 1)->queryOne();
$post2 = $command->bindValue(':id', 2)->queryOne();
``` ```
Cuando la consulta solo devuelva un valor escalar, se usará `queryScalar`: Porque [[yii\db\Command::bindParam()|bindParam()]] soporta parámetros vinculados por referencias, el código de arriba también
puede ser escrito como lo siguiente:
```php ```php
$command = $connection->createCommand('SELECT COUNT(*) FROM post'); $command = $db->createCommand('SELECT * FROM post WHERE id=:id')
$postCount = $command->queryScalar(); ->bindParam(':id', $id);
$id = 1;
$post1 = $command->queryOne();
$id = 2;
$post2 = $command->queryOne();
``` ```
### Ejecución de Consultas que No Devuelvan Valores Observe que vincula el placeholder a la variable `$id` antes de la ejecución, y entonces cambia el valor de esa variable
antes de cada subsiguiente ejecución (esto se hace a menudo con bucles). Ejecutando consultas de esta manera puede ser
bastante más eficiente que ejecutar una nueva consulta para cada valor diferente del parámetro.
Si el SQL ejecutado no devuelve ningún dato, por ejemplo, INSER, UPDATE, y DELETE, se puede usar el método `execute`:
### Ejecutando Consultas Non-SELECT <span id="non-select-queries"></span>
El método `queryXyz()` introducidos en las secciones previas todos tratan con consultas SELECT los cuales recogen los
datos de la base de datos. Para las consultas que no devuelven datos, deberías llamar a el método [[yii\db\Command::execute()]]
en su lugar. Por ejemplo,
```php ```php
$command = $connection->createCommand('UPDATE post SET status=1 WHERE id=1'); $db->createCommand('UPDATE post SET status=1 WHERE id=1')
$command->execute(); ->execute();
``` ```
De forma alternativa, se pueden usar los métodos `insert`, `update`, y `delete`. Estos métodos se encargarán de El método [[yii\db\Command::execute()]] retorna el número de filas afectadas por la ejecución SQL.
gestionar el entrecomillado de los nombres de las tablas y de las columnas que se usen en la consulta, y solo se
tendrá que proporcionar los valores necesarios.
[[Se tiene que poner el enlace de documentación aquí.]] Para consultas INSERT, UPDATE y DELETE, en vez de escribir SQLs planos, puedes llamar a [[yii\db\Command::insert()|insert()]],
[[yii\db\Command::update()|update()]], [[yii\db\Command::delete()|delete()]], respectivamente, construyen los correspondientes
SQLs. Estos métodos entrecomillan adecuadamente las tablas y los nombres de columnas y los valores de los parámetros vinculados.
Por ejemplo,
```php ```php
// INSERT // INSERT (table name, column values)
$connection->createCommand()->insert('user', [ $db->createCommand()->insert('user', [
'name' => 'Sam', 'name' => 'Sam',
'age' => 30, 'age' => 30,
])->execute(); ])->execute();
// insertar múltiples filas a la vez // UPDATE (table name, column values, condition)
$connection->createCommand()->batchInsert('user', ['name', 'age'], [ $db->createCommand()->update('user', ['status' => 1], 'age > 30')->execute();
// DELETE (table name, condition)
$db->createCommand()->delete('user', 'status = 0')->execute();
```
Puedes también llamar a [[yii\db\Command::batchInsert()|batchInsert()]] para insertar múltiples filas de una sola vez,
que es mucho más eficiente que insertar una fila de cada vez:
```php
// table name, column names, column values
$db->createCommand()->batchInsert('user', ['name', 'age'], [
['Tom', 30], ['Tom', 30],
['Jane', 20], ['Jane', 20],
['Linda', 25], ['Linda', 25],
])->execute(); ])->execute();
```
// UPDATE
$connection->createCommand()->update('user', ['status' => 1], 'age > 30')->execute();
// DELETE ## Entrecomillado de Tablas y Nombres de Columna <span id="quoting-table-and-column-names"></span>
$connection->createCommand()->delete('user', 'status = 0')->execute();
```
Entrecomillado de los Nombres de las Tablas y las Columnas <span id="quoting-table-and-column-names"></span> Al escribir código de database-agnostic, entrecomillar correctamente los nombres de las tablas y las columnas es a menudo
---------------------------------------------------------- un dolor de cabeza porque las diferentes bases de datos tienen diferentes reglas para entrecomillar los nombres. Para
solventar este problema, puedes usar la siguiente sintaxis de entrecomillado introducido por Yii:
Para hacer que los nombres de las columnas y las tablas sean seguros para usarse en las consultas, se puede utilizar Yii * `[[column name]]`: encierra con dobles corchetes el nombre de una columna que debe ser entrecomillado;
adecuadamente para que los entrecomille: * `{{table name}}`: encierra con dobles llaves el nombre de una tabla que debe ser entrecomillado.
Yii DAO automáticamente convertirá tales construcciones en un SQL con los correspondientes entrecomillados de los nombres de las columnas o tablas.
Por ejemplo,
```php ```php
$sql = "SELECT COUNT([[$column]]) FROM {{table}}"; // ejecuta esta SQL para MySQL: SELECT COUNT(`id`) FROM `employee`
$rowCount = $connection->createCommand($sql)->queryScalar(); $count = $db->createCommand("SELECT COUNT([[id]]) FROM {{%employee}}")
->queryScalar();
``` ```
En el código anterior, se convertirá `[[$column]]` a un nombre de columna debidamente entrecomillado, mientras que se
convertirá `{{table}}` a un nombre de tabla debidamente entrecomillado.
Hay una variante especial de esta sintaxis especifica para que los nombres de las tablas: `{{%Y}}` añade automáticamente ### Usadno Prefijos de Tabla <span id="using-table-prefix"></span>
el prefijo de la tabla de la aplicación para proporcionar un valor, si se ha establecido un prefijo de tabla:
```php Si la mayoría de tus tablas de BD utilizan algún prefijo común en sus tablas, puedes usar la función de prefijo de tabla soportado
$sql = "SELECT COUNT([[$column]]) FROM {{%table}}"; por Yii DAO.
$rowCount = $connection->createCommand($sql)->queryScalar();
```
El código anterior dará como resultado una consulta de selección de la tabla `tbl_table`, si se tiene el prefijo de Primero, especifica el prefijo de tabla mediante la propiedad [[yii\db\Connection::tablePrefix]]:
tabla configurado como el siguiente:
```php ```php
return [ return [
...@@ -244,113 +299,77 @@ return [ ...@@ -244,113 +299,77 @@ return [
]; ];
``` ```
La alternativa es entrecomillar los nombres de las tablas y las columnas manualmente usando Luego en tu código, siempre que lo necesites para hacer referencia a una tabla cuyo nombre tiene un prefijo, utiliza la sintaxis
[[yii\db\Connection::quoteTableName()]] y [[yii\db\Connection::quoteColumnName()]]: `{{%table name}}`. El carácter porcentaje se sustituye con el prefijo de la tabla que has especificado en la configuración de
la conexión DB. Por ejemplo,
```php ```php
$column = $connection->quoteColumnName($column); // ejecuta esta SQL para MySQL: SELECT COUNT(`id`) FROM `tbl_employee`
$table = $connection->quoteTableName($table); $count = $db->createCommand("SELECT COUNT([[id]]) FROM {{%employee}}")
$sql = "SELECT COUNT($column) FROM $table"; ->queryScalar();
$rowCount = $connection->createCommand($sql)->queryScalar();
``` ```
Uso de Sentencias Preparadas
----------------------------
Para pasar parámetros seguros a las consultas, se deben usar las sentencias preparadas. Primero, se tiene que crear un ## Realización de Transacciones <span id="performing-transactions"></span>
*parámetro de substitución* (placeholder) en una consulta (usando la sintaxis `:placeholder`). Después intercambiar el
parámetro de substitución por una variable y ejecutar la consulta:
```php Cuando se ejecutan múltiples consultas relacionadas en una secuencia, puede que se tengan que envolver en una
$command = $connection->createCommand('SELECT * FROM post WHERE id=:id'); transacción para asegurar la integridad de los datos y la consistencia de tu base de datos. Si cualquiera de las consultas
$command->bindValue(':id', $_GET['id']); falla, la base de datos debe ser revertida al estado anterior como si ninguna de estas consultas se haya ejecutado.
$post = $command->queryOne();
```
Otra finalidad de las sentencias preparadas (aparte de mejorar la seguridad) es la habilidad de ejecutar una consulta El siguiente código muestra una manera típica de usar transacciones:
múltiples veces mientras que sólo se ha preparado una vez:
```php ```php
$command = $connection->createCommand('DELETE FROM post WHERE id=:id'); $db->transaction(function($db) {
$command->bindParam(':id', $id); $db->createCommand($sql1)->execute();
$db->createCommand($sql2)->execute();
$id = 1; // ... ejecutando otras sentencias SQL
$command->execute(); });
$id = 2;
$command->execute();
``` ```
Tenga en cuenta que se efectúa la asignación del parámetro de substitución antes de su ejecución, y después se cambia El código de arriba es equivalente a lo siguiente:
el valor antes de la siguiente ejecución (normalmente se ejecuta en bucles). La ejecución de consultas con este
método, puede ser mucho más eficiente que la ejecución de una consulta cada vez.
Realización de Transacciones
----------------------------
Cuando se ejecutan múltiples, consultas relacionadas en una secuencia, puede que se tengan que envolver en una
transacción para proteger la integridad de los datos. Las transacciones permiten escribir una serie de consultas de
forma que o todas se ejecutan correctamente o no tendrán ningún efecto. Yii proporciona una interfaz sencilla para
trabajar con transacciones en casos simples pero también para el uso avanzado cuando tengan que definir los niveles de
aislamiento.
El siguiente código muestra un patrón simple que debe seguir todo código que utilice consultas transaccionales:
```php ```php
$transaction = $connection->beginTransaction(); $transaction = $db->beginTransaction();
try { try {
$connection->createCommand($sql1)->execute(); $db->createCommand($sql1)->execute();
$connection->createCommand($sql2)->execute(); $db->createCommand($sql2)->execute();
// ... executing other SQL statements ... // ... ejecutando otras sentencias SQL
$transaction->commit(); $transaction->commit();
} catch(\Exception $e) { } catch(\Exception $e) {
$transaction->rollBack(); $transaction->rollBack();
throw $e; throw $e;
} }
``` ```
La primera linea empieza una nueva transacción usando el método Al llamar al método [[yii\db\Connection::beginTransaction()|beginTransaction()]], se inicia una nueva transacción.
[[yii\db\Connection::beginTransaction()|beginTransaction()]] del objeto de conexión a la base de datos. La transacción La transacción se representa como un objeto [[yii\db\Transaction]] almacenado en la variable `$transaction`. Luego,
en si misma se representa con el objeto [[yii\db\Transaction]] almacenado en `$transaction`. Nosotros encapsulamos la las consultas que se ejecutan están encerrados en un bloque `try...catch...`. Si todas las consultas son ejecutadas satisfactoriamente,
ejecución de todas las consultas en un bloque try-catch para poder gestionar los errores. Llamamos a el método [[yii\db\Transaction::commit()|commit()]] es llamado para confirmar la transacción. De lo contrario, una excepción
[[yii\db\Transaction::commit()|commit()]] cuando todo es correcto para efectuar la transacción y si sucede algún error se disparará y se capturará, y el método [[yii\db\Transaction::rollBack()|rollBack()]] es llamado para revertir
ejecutamos [[yii\db\Transaction::rollBack()|rollBack()]]. Esto revertirá el efecto de todas las consultas que se hayan los cambios hechos por las consultas antes de que fallara la consulta en la transacción.
ejecutado dentro de la transacción. Se usa `throw $e` para relanzar la excepción en caso de que nosotros no podamos
gestionar el error y se delega a otro código del gestor de errores de Yii.
Es posible anidar múltiples transacciones si es necesario:
```php ### Especificando los Niveles de Aislamiento <span id="specifying-isolation-levels"></span>
// transacción exterior
$transaction1 = $connection->beginTransaction();
try {
$connection->createCommand($sql1)->execute();
// transacción interior Yii también soporta la configuración de [niveles de aislamiento] para tus transacciones. Por defecto, cuando comienza una nueva transacción,
$transaction2 = $connection->beginTransaction(); utilizará el nivel de aislamiento definido por tu sistema de base de datos. Se puede sobrescribir el nivel de aislamiento por defecto de la
try { siguiente manera,
$connection->createCommand($sql2)->execute();
$transaction2->commit();
} catch (Exception $e) {
$transaction2->rollBack();
}
$transaction1->commit(); ```php
} catch (Exception $e) { $isolationLevel = \yii\db\Transaction::REPEATABLE_READ;
$transaction1->rollBack();
}
```
Tenga en cuanta que el DBMS debe soportar Puntos de Registro (Savepoints) para que funcionen correctamente. El código $db->transaction(function ($db) {
anterior, trabajará con cualquier DBMS pero sólo se garantizarán las transacciones que se ejecuten bajo un DBMS ....
que las soporte. }, $isolationLevel);
Yii también soporta la configuración de [niveles de aislamiento] en las transacciones. Cuando empiece una transacción // or alternatively
se ejecutará con el nivel predeterminado de aislamiento definido por la base de datos. Se puede especificar un nivel
de aislamiento específico cuando se empieza una transacción:
```php $transaction = $db->beginTransaction($isolationLevel);
$transaction = $connection->beginTransaction(\yii\db\Transaction::REPEATABLE_READ);
``` ```
Yii proporciona cuatro constantes para los niveles de aislamiento más comunes: Yii proporciona cuatro constantes para los niveles de aislamiento más comunes:
...@@ -361,35 +380,70 @@ Yii proporciona cuatro constantes para los niveles de aislamiento más comunes: ...@@ -361,35 +380,70 @@ Yii proporciona cuatro constantes para los niveles de aislamiento más comunes:
- [[\yii\db\Transaction::REPEATABLE_READ]] - evita lecturas Dirty y lecturas Non-repeatable. - [[\yii\db\Transaction::REPEATABLE_READ]] - evita lecturas Dirty y lecturas Non-repeatable.
- [[\yii\db\Transaction::SERIALIZABLE]] - el nivel más fuerte, evita todos los problemas nombrados anteriormente. - [[\yii\db\Transaction::SERIALIZABLE]] - el nivel más fuerte, evita todos los problemas nombrados anteriormente.
Se pueden usar las constantes descritas anteriormente aunque también se pueden usar cadenas de texto que representen Además de usar las constantes de arriba para especificar los niveles de aislamiento, puedes también usar cadenas con
la sintaxis que puede ser utilizada en el DBMS seguido de `SET TRANSACTION ISOLATION LEVEL`. Para postgres podría una sintaxis valida soportada por el DBMS que estés usando. Por ejemplo, en PostgreSQL, puedes utilizar `SERIALIZABLE READ ONLY DEFERRABLE`.
utilizarse, por ejemplo, `SERIALIZABLE READ ONLY DEFERRABLE`.
Tenga en cuenta que algunos DBMS permiten configuraciones de niveles de aislamiento solo a nivel de conexión y por Tenga en cuenta que algunos DBMS permiten configuraciones de niveles de aislamiento solo a nivel de conexión. Las transacciones subsiguientes
consiguiente las transacciones pueden obtener el mismo nivel de aislamiento incluso si no se especifica ninguno. recibirá el mismo nivel de aislamiento , incluso si no se especifica ninguna. Al utilizar esta característica
Cuando se usa esta característica, se puede tener que establecer el nivel de aislamiento explícitamente para evitar es posible que necesites ajustar el nivel de aislamiento para todas las transacciones de forma explícitamente para evitar conflictos
conflictos de configuración. En este momento se ven afectados los DBMS MSSQL y SQLite. en las configuraciones.
En el momento de escribir esto, solo MSSQL y SQLite serán afectadas.
> NOTA: SQLite solo soporta dos niveles de aislamiento, por lo que solo se puede usar `READ UNCOMMITTED` y > Nota: SQLite solo soporta dos niveles de aislamiento, por lo que solo se puede usar `READ UNCOMMITTED` y
`SERIALIZABLE`. El uso de otros niveles causará el lanzamiento de una excepción. `SERIALIZABLE`. El uso de otros niveles causará el lanzamiento de una excepción.
> Nota: PostgreSQL no permite configurar el nivel de aislamiento antes que la transacción empiece por lo que no se > Nota: PostgreSQL no permite configurar el nivel de aislamiento antes que la transacción empiece por lo que no se
puede especificar el nivel de aislamiento directamente cuando empieza la transacción. Se tiene que ejecutar puede especificar el nivel de aislamiento directamente cuando empieza la transacción. Se tiene que llamar a
[[yii\db\Transaction::setIsolationLevel()]] después de que la transacción haya empezado. [[yii\db\Transaction::setIsolationLevel()]] después de que la transacción haya empezado.
[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
Réplicas y División Lectura-Escritura
-------------------------------------
Muchos DBMS soportan ### Transacciones Anidadas <span id="nesting-transactions"></span>
[replicación de bases de datos](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication) para tener
Si tu DBMS soporta Savepoint, puedes anidar múltiples transacciones como a continuación:
```php
$db->transaction(function ($db) {
// outer transaction
$db->transaction(function ($db) {
// inner transaction
});
});
```
O alternativamente,
```php
$outerTransaction = $db->beginTransaction();
try {
$db->createCommand($sql1)->execute();
$innerTransaction = $db->beginTransaction();
try {
$db->createCommand($sql2)->execute();
$innerTransaction->commit();
} catch (Exception $e) {
$innerTransaction->rollBack();
}
$outerTransaction->commit();
} catch (Exception $e) {
$outerTransaction->rollBack();
}
```
## Replicación y División Lectura-Escritura <span id="read-write-splitting"></span>
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 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* (master servers) y *servidores esclavos* 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 (slave servers). Todas las escrituras y actualizaciones deben hacerse en el servidor maestro, mientras que las lecturas
se efectuarán en los servidores esclavos. se efectuarán en los servidores esclavos.
Para aprovechar las ventajas de la replicación de BBDD y lograr una división de lecuta-escritura, se puede configurar Para aprovechar las ventajas de la replicación de la base de datos y lograr una división de lecuta-escritura, se puede configurar
el componente [[yii\db\Connection]] como se muestra a continuación: el componente [[yii\db\Connection]] como se muestra a continuación:
```php ```php
...@@ -422,7 +476,7 @@ el componente [[yii\db\Connection]] como se muestra a continuación: ...@@ -422,7 +476,7 @@ el componente [[yii\db\Connection]] como se muestra a continuación:
``` ```
La configuración anterior especifica una configuración con un único maestro y múltiples esclavos. Uno de los esclavos La configuración anterior especifica una configuración con un único maestro y múltiples esclavos. Uno de los esclavos
se conectará y se usará para ejecutar consultas de lectura mientras que el maestro se usará para realizar consultas de se conectará y se usará para ejecutar consultas de lectura, mientras que el maestro se usará para realizar consultas de
escritura. De este modo la división de lectura-escritura se logra automáticamente con esta configuración, Por ejemplo, escritura. De este modo la división de lectura-escritura se logra automáticamente con esta configuración, Por ejemplo,
```php ```php
...@@ -436,14 +490,13 @@ $rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll(); ...@@ -436,14 +490,13 @@ $rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
$db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute(); $db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
``` ```
> Información: Las consultas realizadas ejecutando [[yii\db\Command::execute()]] se consideran consultas de escritura, > Información: 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 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->slave`. 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 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 una consulta de lectura por primera vez, el componente `Connection` elegirá un esclavo aleatorio e intentará realizar
una conexión a este. Si está "muerto", se intentará con otro. Si no está disponible ningún esclavo, se conectará al una conexión a este. Si el esclavo se encuentra "muerto", se intentará con otro. Si no está disponible ningún esclavo, se conectará al maestro. Configurando una [[yii\db\Connection::serverStatusCache|server status cache]], se recordarán los servidores
maestro. Configurando una [[yii\db\Connection::serverStatusCache|server status cache]], se recordarán los servidores
"muertos" por lo que no se intentará volver a conectar a ellos durante "muertos" por lo que no se intentará volver a conectar a ellos durante
[[yii\db\Connection::serverRetryInterval|certain period of time]]. [[yii\db\Connection::serverRetryInterval|certain period of time]].
...@@ -451,7 +504,7 @@ maestro. Configurando una [[yii\db\Connection::serverStatusCache|server status c ...@@ -451,7 +504,7 @@ maestro. Configurando una [[yii\db\Connection::serverStatusCache|server status c
para cada esclavo. Esto significa que si no se puede conectar a un esclavo en 10 segundos, este será considerado para cada esclavo. Esto significa que si no se puede conectar a un esclavo en 10 segundos, este será considerado
como "muerto". Se puede ajustar el parámetro basado en el entorno actual. como "muerto". Se puede ajustar el parámetro basado en el entorno actual.
También se pueden configurar múltiples parámetros para múltiples esclavos. Por ejemplo, También se pueden configurar múltiples maestros con múltiples esclavos. Por ejemplo,
```php ```php
[ [
...@@ -501,8 +554,8 @@ cuando no se encuentra ningún maestro disponible se lanza una excepción. ...@@ -501,8 +554,8 @@ cuando no se encuentra ningún maestro disponible se lanza una excepción.
ignorarán todas las otras propiedades que especifiquen una conexión de base de datos 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`. (ej. `dsn`, `username`, `password`), junto con el mismo objeto `Connection`.
Las conexiones usan la conexión de maestro de forma predeterminada. Y todas las operaciones de BBDD que estén dentro Por defecto. las transacciones usan la conexión del maestro. Y dentro de una transacción, todas las operaciones de DB usarán
de una transacción, usaran la conexión de maestro. Por ejemplo, la conexión del maestro. Por ejemplo,
```php ```php
// la transacción empieza con la conexión al maestro // la transacción empieza con la conexión al maestro
...@@ -520,7 +573,7 @@ try { ...@@ -520,7 +573,7 @@ try {
} }
``` ```
Si se quiere empezar la conexión con una conexión a un esclavo, se debe hacer explícitamente como se muestra a Si se quiere empezar la transacción con una conexión a un esclavo, se debe hacer explícitamente como se muestra a
continuación: continuación:
```php ```php
...@@ -537,47 +590,47 @@ $rows = $db->useMaster(function ($db) { ...@@ -537,47 +590,47 @@ $rows = $db->useMaster(function ($db) {
``` ```
También se puede utilizar directamente estableciendo `$db->enableSlaves` 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 de maestro. consultas a la conexión del maestro.
Trabajar con Esquemas de Bases de Datos ## Trabajando con Esquemas de Bases de Datos <span id="database-schema"></span>
---------------------------------------
Yii DAO proporciona todo un conjunto de métodos que permites manipular el esquema de tu base de datos, tal como
### Obtención de la información del esquema crear nuevas tablas, borrar una columna de una tabla, etc. Estos métodos son listados a continuación:
Se puede obtener una instancia de [[yii\db\Schema]] como se muestra a continuación: * [[yii\db\Command::createTable()|createTable()]]: crea una tabla
* [[yii\db\Command::renameTable()|renameTable()]]: renombra una tabla
```php * [[yii\db\Command::dropTable()|dropTable()]]: remueve una tabla
$schema = $connection->getSchema(); * [[yii\db\Command::truncateTable()|truncateTable()]]: remueve todas las filas de una tabla
``` * [[yii\db\Command::addColumn()|addColumn()]]: añade una columna
* [[yii\db\Command::renameColumn()|renameColumn()]]: renombra una columna
Contiene una serie de métodos que permiten obtener información varia acerca de la base de datos: * [[yii\db\Command::dropColumn()|dropColumn()]]: remueve una columna
* [[yii\db\Command::alterColumn()|alterColumn()]]: altera una columna
* [[yii\db\Command::addPrimaryKey()|addPrimaryKey()]]: añade una clave primaria
* [[yii\db\Command::dropPrimaryKey()|dropPrimaryKey()]]: remueve una clave primaria
* [[yii\db\Command::addForeignKey()|addForeignKey()]]: añade una clave ajena
* [[yii\db\Command::dropForeignKey()|dropForeignKey()]]: remueve una clave ajena
* [[yii\db\Command::createIndex()|createIndex()]]: crea un indice
* [[yii\db\Command::dropIndex()|dropIndex()]]: remueve un indice
Estos métodos puedes ser usados como se muestra a continuación:
```php ```php
$tables = $schema->getTableNames(); // CREATE TABLE
``` $db->createCommand()->createTable('post', [
Para hacer referencia al esquema entero, se puede revisar [[yii\db\Schema]].
### Modificación de esquemas
Aparte de consultas SQL básicas, [[yii\db\Command]] contiene un conjunto de métodos que permiten modificar el esquema
de la base de datos:
- createTable, renameTable, dropTable, truncateTable
- addColumn, renameColumn, dropColumn, alterColumn
- addPrimaryKey, dropPrimaryKey
- addForeignKey, dropForeignKey
- createIndex, dropIndex
Que pueden usarse como se muestra a continuación:
```php
// CREAR TABLA
$connection->createCommand()->createTable('post', [
'id' => 'pk', 'id' => 'pk',
'title' => 'string', 'title' => 'string',
'text' => 'text', 'text' => 'text',
]); ]);
``` ```
Para la referencia completa, se puede revisar [[yii\db\Command]]. También puedes recuperar la información de definición de una tabla a través
del método [[yii\db\Connection::getTableSchema()|getTableSchema()]] de una conexión DB. Por ejemplo,
```php
$table = $db->getTableSchema('post');
```
El método retorna un objeto [[yii\db\TableSchema]] que contiene la información sobre las columnas de las tablas,
claves primarias, claves ajenas, etc. Toda esta información principalmente es utilizada por el
[constructor de consultas](db-query-builder.md) y [active record](db-active-record.md) para ayudar a
escribir código database-agnostic.
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