Tutorial de Ruby / DBI

Este capítulo le enseña cómo acceder a una base de datos usando Ruby. El módulo Ruby DBI proporciona una interfaz independiente de la base de datos para scripts Ruby similar a la del módulo Perl DBI.

DBI significa Interfaz independiente de base de datos para Ruby, lo que significa que DBI proporciona una capa de abstracción entre el código Ruby y la base de datos subyacente, lo que le permite cambiar las implementaciones de la base de datos con mucha facilidad. Define un conjunto de métodos, variables y convenciones que proporcionan una interfaz de base de datos coherente, independiente de la base de datos real que se utiliza.

DBI puede interactuar con lo siguiente:

  • ADO (objetos de datos ActiveX)
  • DB2
  • Frontbase
  • mSQL
  • MySQL
  • ODBC
  • Oracle
  • OCI8 (Oracle)
  • PostgreSQL
  • Proxy/Server
  • SQLite
  • SQLRelay

Arquitectura de una aplicación DBI

DBI es independiente de cualquier base de datos disponible en el backend. Puede usar DBI ya sea que esté trabajando con Oracle, MySQL o Informix, etc. Esto queda claro en el siguiente diagrama de arquitectura.

La arquitectura general de Ruby DBI utiliza dos capas:

  • La capa de interfaz de base de datos (DBI). Esta capa es independiente de la base de datos y proporciona un conjunto de métodos de acceso comunes que se utilizan de la misma manera, independientemente del tipo de servidor de base de datos con el que se esté comunicando.

  • La capa del controlador de base de datos (DBD). Esta capa depende de la base de datos; diferentes controladores proporcionan acceso a diferentes motores de base de datos. Hay un controlador para MySQL, otro para PostgreSQL, otro para InterBase, otro para Oracle y así sucesivamente. Cada controlador interpreta las solicitudes de la capa DBI y las asigna a las solicitudes apropiadas para un tipo determinado de servidor de base de datos.

Prerrequisitos

Si desea escribir scripts Ruby para acceder a bases de datos MySQL, necesitará tener instalado el módulo Ruby MySQL.

Este módulo actúa como DBD como se explicó anteriormente y se puede descargar desde https://www.tmtm.org/en/mysql/ruby/

Obtener e instalar Ruby / DBI

Puede descargar e instalar el módulo Ruby DBI desde la siguiente ubicación:

https://imgur.com/NFEuWe4/embed

Antes de comenzar esta instalación, asegúrese de tener el privilegio de root. Ahora, siga los pasos que se indican a continuación:

Paso 1

$ tar zxf dbi-0.2.0.tar.gz

Paso 2

Vaya al directorio de distribución dbi-0.2.0 y configúrelo usando el script setup.rb en ese directorio. El comando de configuración más general se ve así, sin argumentos después del argumento de configuración. Este comando configura la distribución para instalar todos los controladores de forma predeterminada.

$ ruby setup.rb config

Para ser más específico, proporcione una opción --with que enumere las partes particulares de la distribución que desea usar. Por ejemplo, para configurar solo el módulo DBI principal y el controlador de nivel DBD de MySQL, emita el siguiente comando:

$ ruby setup.rb config --with = dbi,dbd_mysql

Paso 3

El último paso es compilar el controlador e instalarlo usando los siguientes comandos:

$ ruby setup.rb setup
$ ruby setup.rb install

Conexión de base de datos

Suponiendo que vamos a trabajar con la base de datos MySQL, antes de conectarnos a una base de datos asegúrese de lo siguiente:

  • Ha creado una base de datos TESTDB.

  • Ha creado EMPLOYEE en TESTDB.

  • Esta tabla tiene campos FIRST_NAME, APELLIDO, EDAD, SEXO e INGRESOS.

  • El ID de usuario "testuser" y la contraseña "test123" están configurados para acceder a TESTDB.

  • Ruby Module DBI está instalado correctamente en su máquina.

  • Ha seguido el tutorial de MySQL para comprender los conceptos básicos de MySQL.

A continuación se muestra el ejemplo de conexión con la base de datos MySQL "TESTDB"

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   # get server version string and display it
   row = dbh.select_one("SELECT VERSION()")
   puts "Server version: " + row[0]
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

Al ejecutar este script, produce el siguiente resultado en nuestra máquina Linux.

Server version: 5.0.45

Si se establece una conexión con la fuente de datos, se devuelve un identificador de base de datos y se guarda en dbh para uso posterior de lo contrario dbhse establece en un valor nulo y e.err y e :: errstr devuelven el código de error y una cadena de error respectivamente.

Finalmente, antes de publicarlo, asegúrese de que la conexión a la base de datos esté cerrada y los recursos estén liberados.

INSERTAR Operación

La operación INSERT es necesaria cuando desea crear sus registros en una tabla de base de datos.

Una vez que se establece una conexión a la base de datos, estamos listos para crear tablas o registros en las tablas de la base de datos utilizando do método o prepare y execute método.

Uso de declaración do

Las declaraciones que no devuelven filas se pueden emitir invocando la dométodo de manejo de base de datos. Este método toma un argumento de cadena de declaración y devuelve un recuento del número de filas afectadas por la declaración.

dbh.do("DROP TABLE IF EXISTS EMPLOYEE")
dbh.do("CREATE TABLE EMPLOYEE (
   FIRST_NAME  CHAR(20) NOT NULL,
   LAST_NAME  CHAR(20),
   AGE INT,  
   SEX CHAR(1),
   INCOME FLOAT )" );

De manera similar, puede ejecutar la instrucción SQL INSERT para crear un registro en la tabla EMPLOYEE.

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   dbh.do( "INSERT INTO EMPLOYEE(FIRST_NAME, LAST_NAME, AGE, SEX, INCOME)
      VALUES ('Mac', 'Mohan', 20, 'M', 2000)" )
   puts "Record has been created"
   dbh.commit
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

Usando preparar y ejecutar

Puede utilizar métodos de preparación y ejecución de la clase DBI para ejecutar la instrucción SQL a través del código Ruby.

La creación de registros sigue los siguientes pasos:

  • Preparación de la declaración SQL con la declaración INSERT. Esto se hará usando elprepare método.

  • Ejecutando consulta SQL para seleccionar todos los resultados de la base de datos. Esto se hará usando elexecute método.

  • Manija de declaración de liberación. Esto se hará usandofinish API

  • Si todo va bien, entonces commit esta operación de lo contrario puede rollback la transacción completa.

A continuación se muestra la sintaxis para utilizar estos dos métodos:

sth = dbh.prepare(statement)
sth.execute
   ... zero or more SQL operations ...
sth.finish

Estos dos métodos se pueden utilizar para aprobar bindvalores a sentencias SQL. Puede darse el caso de que los valores que se introduzcan no se proporcionen de antemano. En tal caso, se utilizan valores vinculantes. Un signo de interrogación (?) se usa en lugar de los valores reales y luego los valores reales se pasan a través de la API execute ().

A continuación se muestra el ejemplo para crear dos registros en la tabla EMPLOYEE:

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare( "INSERT INTO EMPLOYEE(FIRST_NAME, LAST_NAME, AGE, SEX, INCOME)
      VALUES (?, ?, ?, ?, ?)" )
   sth.execute('John', 'Poul', 25, 'M', 2300)
   sth.execute('Zara', 'Ali', 17, 'F', 1000)
   sth.finish
   dbh.commit
   puts "Record has been created"
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

Si hay varios INSERTs a la vez, entonces preparar una declaración primero y luego ejecutarla varias veces dentro de un ciclo es más eficiente que invocar a do cada vez a través del ciclo.

Operación LEER

READ Operar en cualquier base de datos significa obtener información útil de la base de datos.

Una vez que se establezca nuestra conexión a la base de datos, estamos listos para realizar una consulta en esta base de datos. Podemos usar cualquierado método o prepare y execute métodos para obtener valores de una tabla de base de datos.

La búsqueda de registros toma los siguientes pasos:

  • Preparación de consultas SQL según las condiciones requeridas. Esto se hará usando elprepare método.

  • Ejecutando consulta SQL para seleccionar todos los resultados de la base de datos. Esto se hará usando elexecute método.

  • Obteniendo todos los resultados uno por uno e imprimiéndolos. Esto se hará usando elfetch método.

  • Manija de declaración de liberación. Esto se hará usando elfinish método.

A continuación se muestra el procedimiento para consultar todos los registros de la tabla EMPLEADO que tengan un salario superior a 1000.

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare("SELECT * FROM EMPLOYEE WHERE INCOME > ?")
   sth.execute(1000)

   sth.fetch do |row|
   printf "First Name: %s, Last Name : %s\n", row[0], row[1]
   printf "Age: %d, Sex : %s\n", row[2], row[3]
   printf "Salary :%d \n\n", row[4]
end
   sth.finish
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

Esto producirá el siguiente resultado:

First Name: Mac, Last Name : Mohan
Age: 20, Sex : M
Salary :2000

First Name: John, Last Name : Poul
Age: 25, Sex : M
Salary :2300

Hay más métodos abreviados para recuperar registros de la base de datos. Si está interesado, vaya a Obtener el resultado; de lo contrario, continúe con la siguiente sección.

Operación de actualización

ACTUALIZAR Operar en cualquier base de datos significa actualizar uno o más registros, que ya están disponibles en la base de datos. A continuación se muestra el procedimiento para actualizar todos los registros que tengan SEXO como 'M'. Aquí, aumentaremos la EDAD de todos los machos en un año. Esto tomará tres pasos:

  • Preparación de consultas SQL según las condiciones requeridas. Esto se hará usando elprepare método.

  • Ejecutando consulta SQL para seleccionar todos los resultados de la base de datos. Esto se hará usando elexecute método.

  • Manija de declaración de liberación. Esto se hará usando elfinish método.

  • Si todo va bien entonces commit esta operación de lo contrario puede rollback la transacción completa.

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare("UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = ?")
   sth.execute('M')
   sth.finish
   dbh.commit
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

Operación DELETE

La operación DELETE es necesaria cuando desea eliminar algunos registros de su base de datos. A continuación se muestra el procedimiento para eliminar todos los registros de EMPLEADO donde EDAD es mayor de 20. Esta operación tomará los siguientes pasos.

  • Preparación de consultas SQL según las condiciones requeridas. Esto se hará usando elprepare método.

  • Ejecución de una consulta SQL para eliminar los registros necesarios de la base de datos. Esto se hará usando elexecute método.

  • Manija de declaración de liberación. Esto se hará usando elfinish método.

  • Si todo va bien entonces commit esta operación de lo contrario puede rollback la transacción completa.

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare("DELETE FROM EMPLOYEE WHERE AGE > ?")
   sth.execute(20)
   sth.finish
   dbh.commit
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

Realización de transacciones

Las transacciones son un mecanismo que garantiza la coherencia de los datos. Las transacciones deben tener las siguientes cuatro propiedades:

  • Atomicity - O se completa una transacción o no ocurre nada.

  • Consistency - Una transacción debe comenzar en un estado consistente y dejar el sistema en un estado consistente.

  • Isolation - Los resultados intermedios de una transacción no son visibles fuera de la transacción actual.

  • Durability - Una vez que se ha comprometido una transacción, los efectos son persistentes, incluso después de una falla del sistema.

El DBI proporciona dos métodos para confirmar o deshacer una transacción. Hay un método más llamado transacción que se puede utilizar para implementar transacciones. Hay dos enfoques simples para implementar transacciones:

Acércate yo

El primer enfoque utiliza los métodos de compromiso y retroceso de DBI para confirmar o cancelar explícitamente la transacción:

dbh['AutoCommit'] = false # Set auto commit to false.
begin
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'John'")
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'Zara'")
   dbh.commit
rescue
   puts "transaction failed"
   dbh.rollback
end
dbh['AutoCommit'] = true

Enfoque II

El segundo enfoque utiliza el método de transacción . Esto es más simple, porque se necesita un bloque de código que contiene las declaraciones que componen la transacción. El método de transacción ejecuta el bloque, luego invoca el compromiso o la reversión automáticamente, dependiendo de si el bloque tiene éxito o falla.

dbh['AutoCommit'] = false # Set auto commit to false.
dbh.transaction do |dbh|
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'John'")
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'Zara'")
end
dbh['AutoCommit'] = true

Operación COMMIT

Confirmar es la operación, que da una señal verde a la base de datos para finalizar los cambios, y después de esta operación, ningún cambio puede revertirse.

Aquí hay un ejemplo simple para llamar al commit método.

dbh.commit

Operación ROLLBACK

Si no está satisfecho con uno o más de los cambios y desea revertirlos por completo, utilice el rollback método.

Aquí hay un ejemplo simple para llamar al rollback método.

dbh.rollback

Desconexión de la base de datos

Para desconectar la conexión de la base de datos, use la API de desconexión.

dbh.disconnect

Si el usuario cierra la conexión a una base de datos con el método de desconexión, el DBI revierte cualquier transacción pendiente. Sin embargo, en lugar de depender de cualquiera de los detalles de implementación de DBI, sería mejor que su aplicación llamara a la confirmación o reversión explícitamente.

Manejo de errores

Hay muchas fuentes de errores. Algunos ejemplos son un error de sintaxis en una instrucción SQL ejecutada, un error de conexión o una llamada al método de recuperación para un identificador de instrucción ya cancelado o terminado.

Si un método DBI falla, DBI genera una excepción. Los métodos DBI pueden generar cualquiera de varios tipos de excepción, pero las dos clases de excepción más importantes son DBI :: InterfaceError y DBI :: DatabaseError .

Los objetos de excepción de estas clases tienen tres atributos denominados err , errstr y state , que representan el número de error, una cadena de error descriptiva y un código de error estándar. Los atributos se explican a continuación:

  • err- Devuelve una representación entera del error ocurrido o nulo si no es compatible con DBD. Oracle DBD, por ejemplo, devuelve la parte numérica de un mensaje de error ORA-XXXX .

  • errstr - Devuelve una representación de cadena del error ocurrido.

  • state- Devuelve el código SQLSTATE del error ocurrido. SQLSTATE es una cadena de cinco caracteres. La mayoría de DBD no admiten esto y devuelven nil en su lugar.

Ha visto el siguiente código anterior en la mayoría de los ejemplos:

rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

Para obtener información de depuración sobre lo que hace su script mientras se ejecuta, puede habilitar el seguimiento. Para hacer esto, primero debe cargar el módulo dbi / trace y luego llamar al método de rastreo que controla el modo de rastreo y el destino de salida -

require "dbi/trace"
..............

trace(mode, destination)

El valor de modo puede ser 0 (desactivado), 1, 2 o 3, y el destino debe ser un objeto IO. Los valores predeterminados son 2 y STDERR, respectivamente.

Bloques de código con métodos

Hay algunos métodos que crean identificadores. Estos métodos se pueden invocar con un bloque de código. La ventaja de usar el bloque de código junto con los métodos es que proporcionan el identificador del bloque de código como su parámetro y limpian automáticamente el identificador cuando el bloque termina. Hay pocos ejemplos para comprender el concepto.

  • DBI.connect- Este método genera un identificador de base de datos y se recomienda llamar a desconectar al final del bloque para desconectar la base de datos.

  • dbh.prepare- Este método genera un identificador de declaración y se recomienda terminar al final del bloque. Dentro del bloque, es necesario llamar al ejecutar el método para ejecutar la instrucción.

  • dbh.execute- Este método es similar excepto que no necesitamos invocar la ejecución dentro del bloque. El identificador de instrucciones se ejecuta automáticamente.

Ejemplo 1

DBI.connect puede tomar un bloque de código, le pasa el identificador de la base de datos y desconecta automáticamente el identificador al final del bloque de la siguiente manera.

dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123") do |dbh|

Ejemplo 2

dbh.prepare puede tomar un bloque de código, le pasa el identificador de instrucción y automáticamente llama al final al final del bloque de la siguiente manera.

dbh.prepare("SHOW DATABASES") do |sth|
   sth.execute
   puts "Databases: " + sth.fetch_all.join(", ")
end

Ejemplo 3

dbh.execute puede tomar un bloque de código, le pasa el identificador de declaración y automáticamente las llamadas terminan al final del bloque de la siguiente manera:

dbh.execute("SHOW DATABASES") do |sth|
   puts "Databases: " + sth.fetch_all.join(", ")
end

El método de transacción DBI también toma un bloque de código que se ha descrito anteriormente.

Funciones y atributos específicos del controlador

El DBI permite que los controladores de la base de datos proporcionen funciones adicionales específicas de la base de datos, que el usuario puede llamar a través del método func de cualquier objeto Handle.

Los atributos específicos del controlador son compatibles y se pueden configurar u obtener utilizando el []= o [] métodos.

No Señor. Funciones y descripción
1

dbh.func(:createdb, db_name)

Crea una nueva base de datos.

2

dbh.func(:dropdb, db_name)

Elimina una base de datos.

3

dbh.func(:reload)

Realiza una operación de recarga.

4

dbh.func(:shutdown)

Apaga el servidor.

5

dbh.func(:insert_id) => Fixnum

Devuelve el valor AUTO_INCREMENT más reciente de una conexión.

6

dbh.func(:client_info) => String

Devuelve la información del cliente MySQL en términos de versión.

7

dbh.func(:client_version) => Fixnum

Devuelve la información del cliente en términos de versión. Es similar a: client_info pero devuelve un fixnum en lugar de sting.

8

dbh.func(:host_info) => String

Devuelve información del host.

9

dbh.func(:proto_info) => Fixnum

Devuelve el protocolo que se utiliza para la comunicación.

10

dbh.func(:server_info) => String

Devuelve la información del servidor MySQL en términos de versión.

11

dbh.func(:stat) => String

Devuelve el estado actual de la base de datos.

12

dbh.func(:thread_id) => Fixnum

Devuelve el ID del hilo actual.

Ejemplo

#!/usr/bin/ruby

require "dbi"
begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123") 
   puts dbh.func(:client_info)
   puts dbh.func(:client_version)
   puts dbh.func(:host_info)
   puts dbh.func(:proto_info)
   puts dbh.func(:server_info)
   puts dbh.func(:thread_id)
   puts dbh.func(:stat)
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
ensure
   dbh.disconnect if dbh
end

Esto producirá el siguiente resultado:

5.0.45
50045
Localhost via UNIX socket
10
5.0.45
150621
Uptime: 384981  Threads: 1  Questions: 1101078  Slow queries: 4 \
Opens: 324  Flush tables: 1  Open tables: 64  \
Queries per second avg: 2.860