- Principios de las operaciones de base de datos en MQL5
- Conceptos básicos de SQL
- Estructura de las tablas: tipos de datos y restricciones
- POO (MQL5) e integración SQL: concepto de ORM
- Crear, abrir y cerrar bases de datos
- Ejecutar consultas sin enlace de datos MQL5
- Comprobar si una tabla existe en la base de datos
- Preparar consultas vinculadas: DatabasePrepare
- Borrar y reiniciar consultas preparadas
- Vincular datos a parámetros de consulta: DatabaseBind/Array
- Ejecutar consultas preparadas: DatabaseRead/Bind
- Leer campos por separado: funciones DatabaseColumn
- Ejemplos de operaciones CRUD en SQLite mediante objetos ORM
- Transacciones
- Importar y exportar tablas de bases de datos
- Imprimir tablas y consultas SQL en registros
- Ejemplo de búsqueda de una estrategia de trading mediante SQLite
Transacciones
SQLite admite transactions: conjuntos de acciones relacionadas lógicamente que pueden realizarse por completo o no realizarse en absoluto, lo que garantiza la coherencia de los datos en la base de datos.
El concepto de transaction tiene un nuevo significado en el contexto de las bases de datos, diferente del que solíamos describir en transacciones de trading Una operación de trading es una operación independiente sobre las entidades de una cuenta de trading, incluidas las órdenes, las transacciones y las posiciones.
Las transacciones proporcionan 4 características principales de los cambios en bases de datos:
- Atómico (indivisible) - al finalizar con éxito la transacción, todos los cambios incluidos en ella llegarán a la base de datos, y en caso de error, no llegará nada.
- Consistente - el estado actual correcto de la base sólo puede cambiar a otro estado correcto (los estados intermedios, según la lógica de la aplicación, están excluidos).
- Aislado - los cambios en la transacción de la conexión actual no son visibles hasta el final de esta transacción en otras conexiones a la misma base de datos y viceversa, los cambios de otras conexiones no son visibles en la conexión actual mientras haya una transacción incompleta.
- Duradero - se garantiza que los cambios de una transacción correcta se almacenan en la base de datos.
Los términos para estas características - Atómico, Consistente, Aislado y Duradero - forman el acrónimo ACID (por sus siglas en inglés), bien conocido en la teoría de bases de datos.
Aunque el curso normal del programa se interrumpa debido a un fallo del sistema, la base de datos conservará su estado de funcionamiento.
La mayoría de las veces, el uso de las transacciones se ilustra con el ejemplo de un sistema bancario, en el que se transfieren fondos de la cuenta de un cliente a la cuenta de otro. Debe afectar a dos registros con saldos de clientes: en uno, el saldo se reduce por el importe de la transferencia, y en el otro, se incrementa. Una situación en la que sólo se aplicara uno de estos cambios alteraría el saldo de las cuentas bancarias: dependiendo de qué operación falle, el importe transferido podría desaparecer o, por el contrario, surgir de la nada.
Es posible ofrecer un ejemplo más cercano a la práctica de trading, pero basado en el principio «opuesto». El hecho es que el sistema de contabilización de órdenes, transacciones y posiciones en MetaTrader 5 no es transaccional.
En particular, como sabemos por el capítulo Crear Asesores Expertos, una orden activada (de mercado o pendiente), que falte en la lista de activas, puede no aparecer inmediatamente en la lista de posiciones. Por lo tanto, para analizar el resultado real, es necesario implementar en el programa MQL la expectativa de actualización del entorno de trading. Si el sistema contable se basara en transacciones, la ejecución de una orden, el registro de una transacción en el historial y la aparición de una posición se englobarían en una transacción y se coordinarían entre sí. Los desarrolladores del terminal han optado por un enfoque diferente: devolver cualquier modificación del entorno de trading lo más rápida y asíncronamente posible, y su integridad debe ser supervisada por un programa MQL.
Cualquier comando SQL que cambie la base (es decir, de hecho, todo excepto SELECT) se envolverá automáticamente en una transacción si esto no se hizo explícitamente de antemano.
La API de MQL5 proporciona 3 funciones para gestionar las transacciones: DatabaseTransactionBegin, DatabaseTransactionCommit y DatabaseTransactionRollback. Todas las funciones devuelven true en caso de éxito, o false en caso de error.
bool DatabaseTransactionBegin(int database)
La función DatabaseTransactionBegin inicia la ejecución de una transacción en la base de datos con el descriptor especificado obtenido de DatabaseOpen.
Todos los cambios posteriores realizados en la base de datos se acumulan en la caché interna de transacciones y no llegan a la base de datos hasta que se llama a la función DatabaseTransactionCommit.
Las transacciones en MQL5 no se pueden anidar: si una transacción ya se ha iniciado, entonces volver a llamar a DatabaseTransactionBegin devolverá una bandera de error y la salida de un mensaje en el registro.
database error, cannot start a transaction within a transaction
|
Respectivamente, no puede intentar completar la transacción varias veces.
bool DatabaseTransactionCommit(int database)
La función DatabaseTransactionCommit finaliza una transacción iniciada previamente en la base de datos con el manejador especificado y aplica todos los cambios acumulados (los guarda). Si un programa MQL inicia una transacción pero no la aplica antes de cerrar la base de datos, se perderán todos los cambios.
Si es necesario, el programa puede deshacer la transacción y, por tanto, todos los cambios desde el inicio de la transacción.
bool DatabaseTransactionRollback(int database)
La función DatabaseTransactionRollback realiza un «retroceso» de todas las acciones incluidas en la transacción iniciada previamente para la base de datos con el manejador database.
Vamos a completar los métodos de la clase DBSQLite para trabajar con transacciones, teniendo en cuenta la restricción en su anidamiento, que calcularemos en la variable transaction. Si es 0, el método begin inicia una transacción llamando a DatabaseTransactionBegin. Todos los intentos posteriores de iniciar una transacción simplemente aumentan el contador. En el método commit, reducimos el contador, y cuando llega a 0 llamamos a DatabaseTransactionCommit.
class DBSQLite
|
Además, vamos a crear la clase DBTransaction, que permitirá describir objetos dentro de bloques (por ejemplo, funciones) que aseguren el inicio automático de una transacción con su posterior aplicación (o cancelación) cuando el programa salga del bloque.
class DBTransaction
|
La política de utilizar este tipo de objetos elimina la necesidad de procesar varias opciones para salir de un bloque (función).
void DataFunction(DBSQLite &db)
|
Para que un objeto aplique automáticamente los cambios en cualquier fase, pase true en el segundo parámetro de su constructor.
void DataFunction(DBSQLite &db)
|
Puede describir el objeto DBTransaction dentro del bucle y entonces, en cada iteración, se iniciará y cerrará una transacción independiente.
Se hará una demostración de las transacciones en la sección Ejemplo de búsqueda de una estrategia de trading mediante SQLite.