Søger du en specifik kategori?

 



Oprettet tor. d. 05. februar 2009 kl. 16:30

arne_v
arne_v (1.016.094 point)
Guidens karaktér
1
2
3
4
5

Brug af MySQL i C++

Denne artikel bygger ovenpå artiklen "MySQL C API" og forklarer hvordan man kan programmere mere objekt orienteret. Den forudsætter kendskab til C++ og lidt kendskab til SQL og MySQL C API.
[vigtigt: artikel 244 er samme artikel som denne - der gik
koks i det i forbindelse med de 2 store nedbrud på Eksperten
i maj måned - jeg vil ikke slette en af dem af hensyn til
dem som har "betalt" for artiklen]

Historie:
V1.0 - 01/04/2004 - original
V1.1 - 26/12/2008 - små ændringer

Indledning

Artiklen vil vise 3 forskellige tilgange til brug af MySQL fra C++.

Den bruger de samme eksempler som artiklen <a href="http://www.eksperten.dk/ (...) C API</a>.

Der vil kun blive vist build kommandoer for MS VC++. For andre compilere
henvises til førnævnte artikel.

Der vil ikke blive vist MFC/ATL ODBC/OLE DB brug.

Fortsæt med MySQL C API

MySQL C API kan udmærket bruges fra C++.

Eksempel:

query2.cpp


#include <cstdio>
#include <cstdlib>

#include <iostream>

using namespace std;

#include "mysql.h"

int main()
{
    //
    // åben connection til:
    //  server = "localhost"
    //  username = "root"
    //  password = ""
    //  database = "Test"
    //  port = 0 (bliver opfattet som default 3306)
    //
    MYSQL *handle= mysql_init(NULL);
    if(handle == NULL)
    {
        cerr << "MySQL error: " << mysql_error(handle) << endl;
        exit(1);
    }
    if(!mysql_real_connect(handle, "localhost", "root", "", "Test", 0, NULL, 0))
    {
        cerr << "MySQL error: " << mysql_error(handle) << endl;
        exit(1);
    }
    // udfør query
    mysql_query(handle, "SELECT * FROM t1");
    MYSQL_RES *result = mysql_store_result(handle);
    // print resultat af query
    int nfields = mysql_num_fields(result);
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(result))) {
        int *l = (int *)mysql_fetch_lengths(result);
        for (int i=0; i<nfields; i++) {
            char *buf = new char[l[i]+1];
            strncpy(buf,row[i] ? row[i] : "NULL",row[i] ? l[i] : 4);
            buf[row[i] ? l[i] : 4] = '\0';
            cout << " " << buf;
            delete[] buf;
        }
        cout << endl;
    }
    // luk query
    mysql_free_result(result);
    // luk connection
    mysql_close(handle);
    return 0;
}


insert2.cpp


#include <cstdio>
#include <cstdlib>

#include <iostream>

using namespace std;

#include "mysql.h"

int main()
{
    //
    // åben connection til:
    //  server = "localhost"
    //  username = "root"
    //  password = ""
    //  database = "Test"
    //  port = 0 (bliver opfattet som default 3306)
    //
    MYSQL *handle= mysql_init(NULL);
    if(handle == NULL)
    {
        cerr << "MySQL error: " << mysql_error(handle) << endl;
        exit(1);
    }
    if(!mysql_real_connect(handle, "localhost", "root", "", "Test", 0, NULL, 0))
    {
        cerr << "MySQL error: " << mysql_error(handle) << endl;
        exit(1);
    }
    // indsæt 10 rækker
    for(int i=0; i<10; i++)
    {
        char sqlcmd[200];
        sprintf(sqlcmd, "INSERT INTO t1 VALUES (%d,'%s')", i, "Dette er en test");
        mysql_query(handle, sqlcmd);
    }
    // luk connection
    mysql_close(handle);
    return 0;
}


Build MS VC++ 6:

cl /GX /DSOCKET=int /I\mysql\include query2.cpp \mysql\lib\opt\libmysql.lib
cl /GX /DSOCKET=int /I\mysql\include insert2.cpp \mysql\lib\opt\libmysql.lib


Fordele:
* stabilt og kendt API

Ulemper:
* ikke særligt objekt orienteret

MySQL++ API

MySQL har også lavet et specielt C++ API.

Idag vedligeholdes det ikke længere af MySQL og skal hentes herfra:
  <a href="http://tangentsoft.net/ (...)

Eksempel:

query3.cpp


#include <iostream>

using namespace std;

#include "sqlplus.hh"

int main()
{
    try
    {
        //
        // åben connection til:
        //  database = "Test"
        //  server = "localhost"
        //  username = "root"
        //  password = ""
        //
        Connection con("Test", "localhost", "root", "");
        // udfør query
        Query q = con.query();
        q << "SELECT * FROM t1";
        Result res = q.store();
        // print resultat af query
        for (Result::iterator it = res.begin(); it != res.end(); it++)
        {
            Row r = *it;
            for(int i = 0; i < res.columns(); i++)
            {
                cout << " " << (!r[i].is_null() ? r[i] : "NULL");
            }
            cout << endl;
        }
    }
    catch(BadQuery er)
    {
        cerr << "MySQL error: " << er.error << endl;
    }
    return 0;
}


insert3.cpp


#include <iostream>
#include <sstream>

using namespace std;

#include "sqlplus.hh"

int main()
{
    try
    {
        //
        // åben connection til:
        //  database = "Test"
        //  server = "localhost"
        //  username = "root"
        //  password = ""
        //
        Connection con("Test", "localhost", "root", "");
        // indsæt 10 rækker
        Query q = con.query();
        for(int i=0; i<10; i++)
        {
            ostringstream s;
            s << "INSERT INTO t1 VALUES (" << i << ",'Dette er en test')";
            q.exec(s.str());
        }
    }
    catch(BadQuery er)
    {
        cerr << "MySQL error: " << er.error << endl;
    }
    return 0;
}


Build MS VC++ 6:

cl /MD /GX /DSOCKET=int /I\mysql++\include /I\mysql\include query3.cpp \mysql++\lib\mysql++.lib \mysql\lib\opt\mysqlclient.lib
cl /MD /GX /DSOCKET=int /I\mysql++\include /I\mysql\include insert3.cpp \mysql++\lib\mysql++.lib \mysql\lib\opt\mysqlclient.lib


Fordele:
* objekt orienteret
* stort kraftfuldt API
* meget C++'sk

Ulemper:
* meget compiler specifikt og det kan drille rigtigt meget at få det til at virke
* nogen af de avancerede features er implementeret via en 31000 linier header file med #define's
* ligner ikke de objekt orienterede API'er man kender fra C#, Java etc.

Hjemmelavet C++ API

Er man utilfreds med MySQL's C++ API kan man jo lave sit eget.

Her er starten på et simpelt som forsøger at ligne de kendte
objekt orienterede database API'er.

mysqlobj.h


#ifndef MYSQLOBJ_H
#define MYSQLOBJ_H

#include <cstdlib>

#include "mysql.h"

class ResultSet
{
    private:
        MYSQL_RES *result;
        MYSQL_ROW row;
        int *len;
        ResultSet();
        void init(MYSQL *handle, char *sqlcmd);
        friend class Connection;
    public:
        ~ResultSet();
        bool Next();
        int GetNoFields();
        bool IsNull(int ix);
        char *Get(int ix);
        int GetInt(int ix) { return atoi(Get(ix)); };
        double GetDouble(int ix) { return atof(Get(ix)); };
        char *GetString(int ix) { return Get(ix); };
};

class Connection
{
    private:
        MYSQL *handle;
        bool connected;
        ResultSet rs;
    public:
        Connection(char *database, char *host = "localhost", char *user="root", char *pw="", int port=3306);
        ~Connection();
        ResultSet ExecuteQuery(char *sql,...);
        int ExecuteNonQuery(char *sql,...);
        char *GetError();
        inline bool IsConnected() { return connected; };
};

#endif // MYSQLOBJ_H


mysqlobj.cpp


#include <cstdio>
#include <cstdarg>

#include "mysqlobj.h"

ResultSet::ResultSet()
{
    result = NULL;
}

void ResultSet::init(MYSQL *handle, char *sqlcmd)
{
    if(result != NULL)
    {
        mysql_free_result(result);
        result = NULL;
    }
    mysql_query(handle, sqlcmd);
    result = mysql_store_result(handle);
}

ResultSet::~ResultSet()
{
    if(result != NULL)
    {
        mysql_free_result(result);
        result = NULL;
    }
}

bool ResultSet::Next()
{
    row = mysql_fetch_row(result);
    if(row != NULL)
    {
        len = (int *)mysql_fetch_lengths(result);
        return true;
    }
    else
    {
        return false;
    }
}

int ResultSet::GetNoFields()
{
    return mysql_num_fields(result);
}

bool ResultSet::IsNull(int ix)
{
    return (row[ix] == NULL);
}

char *ResultSet::Get(int ix)
{
    return row[ix];
}

Connection::Connection(char *database, char *host, char *user, char *pw, int port) : rs()
{
    handle = mysql_init(NULL);
    if(handle == NULL)
    {
        connected = false;
    }
    else if(!mysql_real_connect(handle, host, user, pw, database, port, NULL, 0))
    {
        connected = false;
    }
    else
    {
        connected = true;
    }
}

Connection::~Connection()
{
    mysql_close(handle);
    connected = false;
}

ResultSet Connection::ExecuteQuery(char *sql,...)
{
    va_list argptr;
    va_start(argptr, sql);
    char buf[10000];
    vsprintf(buf, sql, argptr);
    va_end(argptr);
    rs.init(handle, buf);
    return rs;
}

int Connection::ExecuteNonQuery(char *sql,...)
{
    va_list argptr;
    va_start(argptr, sql);
    char buf[10000];
    vsprintf(buf, sql, argptr);
    va_end(argptr);
    return mysql_query(handle, buf);
}

char *Connection::GetError()
{
    return mysql_error(handle);
}


Eksempel:

query4.cpp


#include <iostream>

using namespace std;

#include "mysqlobj.h"

int main()
{
    //
    // åben connection til:
    //  database = "Test"
    //  server = "localhost" (default)
    //  username = "root" (default)
    //  password = "" (default)
    //  port = 3306 (default)
    //
    Connection con("Test");
    if(!con.IsConnected())
    {
        cerr << con.GetError() << endl;
        exit(1);
    }
    // udfør query
    ResultSet rs = con.ExecuteQuery("SELECT * FROM t1");
    // print resultat af query
    while (rs.Next()) {
        for (int i=0; i<rs.GetNoFields(); i++) {
            cout << " " << (!rs.IsNull(i) ? rs.Get(i) : "NULL");
        }
        cout << endl;
    }
    return 0;
}


insert4.cpp


#include <iostream>

using namespace std;

#include "mysqlobj.h"

int main()
{
    //
    // åben connection til:
    //  database = "Test"
    //  server = "localhost" (default)
    //  username = "root" (default)
    //  password = "" (default)
    //  port = 3306 (default)
    //
    Connection con("Test");
    if(!con.IsConnected())
    {
        cerr << con.GetError() << endl;
        exit(1);
    }
    // indsæt 10 rækker
    for(int i=0; i<10; i++)
    {
        con.ExecuteNonQuery("INSERT INTO t1 VALUES (%d,'%s')", i, "Dette er en test");
    }
    return 0;
}


Build MS VC++ 6:

cl /c /GX /DSOCKET=int /I\mysql\include mysqlobj.cpp
cl /GX /DSOCKET=int /I\mysql\include query4.cpp mysqlobj.obj \mysql\lib\opt\libmysql.lib
cl /GX /DSOCKET=int /I\mysql\include insert4.cpp mysqlobj.obj \mysql\lib\opt\libmysql.lib


Fordele:
* objekt orienteret
* velkendt stil

Ulemper:
* simpelt API
* man skal selv vedligeholde det

Bemærk at mysqlobj.h/mysqlobj.cpp kun er mit forslag. Man kan lave andre varianter.
Men man er meget velkommen til at tage udgangspunkt i mysqlobj.h/mysqlobj.cpp.

MySQL Connector for C++

MySQL har lavet et nye C++ API til erstatning for MySQL++

Det skal hentes separat herfra:
  <a href="http://dev.mysql.com/ (...)

Jeg har endnu ikke prøvet dette API.

Det er stadig kun i alpha udgave og jeg har problemer med bare at få buildet det.

Skrevet fre. d. 07. maj 2004 kl. 20:20| #1

Tror bare jeg foretrækker HTMl ;) /Htmlkongen

Skrevet lør. d. 08. maj 2004 kl. 04:20| #2

danielhep (13.650 point)
sådan skal det gøre :)

Skrevet fre. d. 14. maj 2004 kl. 14:09| #3

playr (11.941 point)
htmlkongen : HTML? Kan da ikke sammenlignes med C++ da HTML ikke kan kører med MYSQL, men det kan PHP og det foretrækker jeg!

Arne : God artikel!

Skrevet fre. d. 01. oktober 2004 kl. 11:29| #4

jakobdo (181.692 point)
www.codebreaker.dk
God artikel, noget man jo nok skal kunne bruge en dag! (har selv forsøgt med C++ + Mysql, og det var ikke en success, men nu forsøger vi da bare igen)

Skrevet søn. d. 15. maj 2005 kl. 15:39| #5

jesperkm (12.748 point)
Perfekt!

Skrevet ons. d. 28. januar 2009 kl. 22:28| #6

mulbo (16.955 point)
Præcis og simpel! Perfekt

Skriv en kommentar



Mest populære guides i Linux - Generelt

Guidens karakter
!!!Karaktér: 4
5 stemmer
24/02 - 2010
Af: mrmox2

Installation af flash og java-support i din foretrukne browser under linux

Java installeres ikke som standard i din browser under linux, og hvis du vil bruge din egen browser, fx firefox, er flash heller ikke installeret. Det tager kun 5 minutter at gøre det.

Log ind

   

   



   




Tips & Tricks fra PC World

Teaser billede

Top 5: Virale YouTube-videoer fra Danmark

Lægger du mærke til de mere eller mindre skjulte reklamebudskaber, når du ser videoer på nettet? Vi har taget et kig på fem utrolige danske videoer, som er blevet virale hit.


Anmeldelser fra PC World

Teaser billede

Test: Mobil med Ferrari-design - og en Trabant-motor

Motorola har begået endnu en smartphone med lækkert design og potentiale til at være blandt de bedste. Men den når ikke i mål. Se her hvorfor.


Seneste blogindlæg

Teaser billede

Tvangslukke spørgsmål: Hvad er den bedste løsning?

Hej Vi har mange åbne spørgsmål på Eksperten. Vi ville gerne tvangslukke dem - så et spørgsmål efter f.eks. 6 måneder lukkes. Men der er et par uklarheder som ville være gode at få lidt input til:...


Nyheder fra PC World

Teaser billede

Sådan fupper smarte svindlere dig på Facebook

Se hvordan du undgår Facebook-fup i fremtiden.


Nyheder fra Computerworld

Teaser billede

App-udvikling 2.0: Sådan er den perfekte app

ComputerViews: Den værste app-hype er ved at have lagt sig, og nu ser vi konturerne af fremtidens app-design. Men hvordan udnytter man de mobile muligheder optimalt?


Kurser
Samarbejdspartnere

Udgiver · © 2012 IDG Danmark A/S · Hørkær 18 · 2730 Herlev · Tlf.: 77 300 300 · Fax: 77 300 301 · Brug af personoplysninger