Comenzando con MySQL Connector/C++

Comments: 6

Para los que venimos de PHP la ausencia de una librería estándar en C++ para trabajar con bases de datos SQL puede resultarnos un tanto extraño. Como tampoco he visto mucha información al respecto, en este artículo voy a centrarme en MySQL Connector/C++, la librería "oficial" de MySQL para C++.

Existen otras librerías como MySQL C API o MySQL++, clase envolvente de la primera. Sin embargo MySQL Connector/C++ parece ser la más avanzada.

Al contrario que las otras, esta API no depende de ninguna función de C y está basada en JDBC. Debemos tener en cuenta que es un producto de MySQL (y por lo tanto de Oracle) y que tiene una licencia dual comercial / GNU GPLv2 con la Excepción FOSS.

Instalación

Lo primero que tenemos que hacer es, obviamente, instalar el servidor mysql si aún no lo tenemos instalado. Para los que manejamos Ubuntu GNU/Linux es sencillo:

$ sudo apt-get install mysql-server

Por cierto, hay que señalar que MySQL Connector/C++ requiere MySQL 5.1 o superior.

A continuación instalamos la librería del conector:

$ sudo apt-get install libmysqlcppconn-dev

O podemos acceder a la propia sección de descargas donde tendremos que seleccionar nuestro sistema operativo.

Una vez hecho esto tenemos que establecer en nuestro IDE el nombre y la localización de los drivers de la librería. Para los que utlizamos Netbeans podemos seguir este pequeño tutorial de planet mysql.

Comenzando a trabajar con la API

A continuación expongo un sencillo ejemplo para entornos Linux. Para simplificarlo he omitido algunos puntos que explicaré más abajo. Vaya por deleante que en este artículo solo recojo -bajo mi punto de vista- los principales métodos, ya que en realidad la API consta de multitud de ellos. Para su consulta debemos acudir a la guía para desarrolladores. Esta guía no es muy extensa pero aún asi es bastante completa.

// Debemos incluir las siguientes cabeceras
#include "mysql_connection.h"
#include <cppconn/driver.h>
#include <cppconn/
resultset.h>

n#include <cppconn/statement.h>
#include <cppconn/exception.h>
        
int main()
{
    sql::Driver *driver;
    sql::Connection *connection;
    sql::Statement *statement;
    sql::ResultSet *resultset;

    // Nos conectamos a nuestro servidor MySQL
    driver = get_driver_instance();
    connection = driver->connect("tcp://127.0.0.1:3306", "root", "");

    // Elegimos una base datos que ya tengamos creada ("prueba")
    connection->setSchema("prueba");

    // Hacemos nuestra primera consulta
    statement = connection->createStatement();
    resultset = statement->executeQuery("SELECT nombre, apellido FROM usuarios");

    // Pintamos el resultado
    while (resultset->next()) {
        std::cout << " Nombre: " << resultset->getString(1);
        std::cout << "\n Apellido: " << resultset->getString(2);
        std::cout << std::endl;
    }

    // Editamos un registro existente
    // La consulta lanza una excepción con un error tipo 0 (éxito)
    try {
        statement->executeQuery("UPDATE usuarios SET apellido='Stroustrup' WHERE id = 1 AND nombre='Bjarne'");
    } catch (sql::SQLException &e) {}

    // Eliminamos los objetos
    delete resultset;
    delete statement;
    delete connection;
}

Para los despistados que sigan el ejemplo a ciegas, hay que tener en cuenta que debemos crear nuestra base de datos "prueba" y que esta ha de contener al menos la tabla "usuarios" con los campos que se señalan en el ejemplo. Una vez hecho esto, compilamos y listo. Por cierto, si vamos a compilar desde la terminal debemos acordarnos de añadir el enlace al conector (-lmysqlcppconn).

Sentencias preparadas

Como no podía ser de otra manera, esta API dispone de métodos para protegernos ante posibles inyecciones sql gracias al objeto PreparedStatement. Reescribimos por lo tanto la segunda consulta a la base de datos del ejemplo anterior de la siguiente manera:

sql::PreparedStatement* prep_statement;

prep_statement = connection->prepareStatement("UPDATE usuarios SET apellido='Stroustrup' WHERE id = ? AND nombre=?");
prep_statement->setInt(1, 1);
prep_statement->setString(2, "Stroustrup");
prep_statement->executeQuery();

Uitlizaremos los métodos setInt() o setString() cuando se trate de elementos tipo int y tipo string, respectivamente. Al final del código debemos acordarnos de destruir este nuevo objeto.

Ejecución de las sentencias SQL

El método executeQuery() nos devuelve el objeto ResultSet que nos permitirá trabajar con el resultado de la consulta. Sin embargo, no siempre necesitaremos obtener este objeto, por ejemplo, cuando hacemos una consulta de tipo INSERT o UPDATE. Para ello disponemos del método executeUpdate() el cual nos permitirá trabajar de forma más óptima . Este método solo nos devolverá el número de filas afectadas por la sentencia.

Por lo tanto, en nuestro ejemplo podemos sustituir la sentencia prep_statement -> executeQuery() por prep_statement -> executeUpdate().

Obtención de los datos

Aquí entran en escena los métodos de la interfaz ResultSet. En el ejemplo hemos utilizado el método getString() para obtener el valor de la consulta pasando como parámetro el índice numérico de cada campo, aunque también podríamos haber pasado directamente el nombre del campo de la manera:

while (resultset->next()) {
    std::cout << "Nombre: " << resultset->
getString("nombre");
    std::cout << "Apellidos: " << resultset->getString("apellidos");
    std::cout << endl;
}

Cuando el dato es de tipo entero podemos utilizar el método getInt(). Además dispomemos de unos cuantos métodos para desplazarnos por las filas resultado. En el ejemplo hemos recurrido al método next() pero existen muchos otros como previous(), last(), first(), etc. cuyo significado entiendo que no hace falta explicar. Si echamos un ojo a la cabecera resultset.h podremos encontrar todos.

¿Una "Wrapper Class"?

A aquellos que como yo lleven poco tiempo con C++, tal vez les sea útil una pequeña clase envolvente que he desarrollado para trabajar con esta librería. No está acabada (y no creo que llegue a estarlo) pero es perfecta para una primera aproximación con el conector. Como siempre, podéis encontrarla en GitHub.

Comments

You must sing in to post a comment.

Eduardo Casas Eduardo Casas

¿Acaso creíais que había abandonado este blog? ¡Pues no!

Acabo de corregir el error que impedía publicar comentarios. ¿Será este el motivo por el que no estaba participando nadie? :P

Muchas gracias a Pablo (http://www.liberapyme.com) por comunicarme el fallo.

Galo Pule Galo Pule

Hola, buen blog.

Sabes cómo iría el comando "g++" para poder compilar un programa cliente c++?

Eduardo Casas Eduardo Casas

¡Hola Galo!

Prueba con esto:
$ g++ tu_fichero_fuente.cpp -o fichero_compilado -lmysqlcppconn

This comment has been edited on
Diego Redondo Diego Redondo

Tengo una consulta, ¿como hago para pasar una variable dentro de la sentencia UPDATE a mysql?

Saludos

Eduardo Casas Eduardo Casas

Diego, no tendrías más que concatenar la variable como lo harías con cualquier otra cadena de texto.

De todas formas ten en cuenta que esto sería una manera de proceder muy poco recomendable. Utiliza siempre sentencias preparadas pare así prevenir posibles ataques a la base de datos.

Pedro Antonio Pedro Antonio

Hola, ¿cómo haría para subir a la base de datos (utilizando INSERT) un valor de nuestro código c++?
Es decir, si mi código c++ dice que "temperatura = 10" una vez que me conecto a la BBDD, ¿cómo introduzco ese dato en la BBDD?

Saludos