Mysql資料庫學習(四):常用Mysql C API 介紹和使用、封裝一個訪問Mysql資料庫的類MysqlDB

s1mba發表於2014-02-28


首先,環境是windows +  vs2008,Mysql資料庫已經安裝好,在使用之前,需要配置工程屬性,附加包含目錄新增

D:\Program Files\MySQL\MySQL Server 5.6\include (Mysql安裝目錄),附加庫目錄新增 D:\Program Files\MySQL\MySQL Server 5.6\lib   ,附加依賴項新增 mysqlib.lib,當然mysqllib.lib 只是包含符號而已,可執行檔案執行的時候需要mysqllib.dll(lib目錄下), 將其拷貝到exe同目錄下。


一、常用Mysql C API 介紹和使用

1.mysql_init

MYSQL結構代表一個連線控制程式碼
MYSQL*mysql_init(MYSQL*mysql);
如果mysql是NULL指標,該函式將分配、初始化、並返回新物件。否則,將初始化物件,並返回物件的地址。如果mysql_init()分配了新的物件,當呼叫mysql_close()來關閉連線時。將釋放該物件。

2.mysql_real_connect

// 連線資料庫
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) 

//設定資料庫
my_bool reconnect = true;
mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "gbk");

3.mysql_query

int mysql_query(MYSQL *mysql, const char *query)
mysql_affected_rows
mysql_store_result
mysql_num_fields
mysql_num_rows
mysql_fetch_field
mysql_fetch_row
mysql_free_result

示例程式碼如下:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

#include <Windows.h>
#include <mysql.h>
#include <stdio.h>

int main(void)
{
    //初始化一個連線控制程式碼
    MYSQL* mysql = mysql_init(NULL);
    if (mysql == NULL)
    {
        printf("error:%s", mysql_error(mysql));
        return 1;
    }
    
    my_bool reconnect = true;
    mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
    mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "gbk");

    if (!mysql_real_connect(mysql, "localhost""root""123456",
        "scott"0NULL0))
    {
        printf("error:%s", mysql_error(mysql));
        return 1;
    }

    // 沒有返回結果集的操作
    int result;
    result = mysql_query(mysql, "insert into emp values(8888, 'YYYY', 'CLERK', 7782, '1990-04-10', 1500, NULL, 50);");
    if (result != 0)
    {
        printf("error:%s", mysql_error(mysql));
        return 1;
    }
    printf("%llu 行受影響\n", mysql_affected_rows(mysql));
    
    // 有返回結果集的操作
    result = mysql_query(mysql, "select * from emp where deptno=30;");
    if (result != 0)
    {
        printf("error:%s", mysql_error(mysql));
        return 1;
    }

    MYSQL_RES* mysql_res;
    MYSQL_FIELD* mysql_field;
    MYSQL_ROW mysql_row;
    unsigned int cols;
    mysql_res = mysql_store_result(mysql);
    cols = mysql_num_fields(mysql_res);

    if (mysql_res != NULL)
    {
        printf("返回%llu行\n", mysql_num_rows(mysql_res));
        while((mysql_field = mysql_fetch_field(mysql_res)))
        {
            printf("%s\t", mysql_field->name);
        }
        printf("\n");

        while((mysql_row = mysql_fetch_row(mysql_res)))
        {
            for (unsigned int i = 0; i < cols; i++)
            {
                printf("%s\t", mysql_row[i]? mysql_row[i]: "NULL");
            }
            printf("\n");
        }
        mysql_free_result(mysql_res);
    }

    mysql_close(mysql);
    return 0;
}

輸出結果如下,因為各欄位值長短不一,雖然加了tab,輸出還是有點彆扭:




二、下面封裝MysqlDB類

使用的基本是上面演示過的函式,就不多解釋了,直接看程式碼吧。

MysqlDB.h:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#ifndef _MYSQL_DB_H_
#define _MYSQL_DB_H_

//#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <mysql.h>

#include <vector>
#include <string>
using namespace std;

namespace DAL
{

class MysqlDB;
class MysqlRecordset
{
    friend class MysqlDB;
public:
    const string& GetItem(unsigned int nRow, unsigned int nCol) const
    {
        return rows_[nRow][nCol];
    }

    const string& GetItem(unsigned int nRow, const string& name) const
    {
        unsigned int index = GetFieldIndex(name);
        return rows_[nRow][index];
    }

    unsigned int GetRows() const
    {
        return rows_.size();
    }

    unsigned int GetCols() const
    {
        return fields_.size();
    }

    unsigned int GetFieldIndex(const std::string &name) const
    {
        unsigned int index = -1;
        for(unsigned int i = 0; i < fields_.size(); ++i)
        {
            if (fields_[i].name == name)
                index = fields_[i].index;
        }
        return index;
    }

    void Clear()
    {
        rows_.clear();
        fields_.clear();
    }

    typedef struct Field
    {
        string name; //列的欄位名
        unsigned int index; //欄位名對應的下標
    } FIELD;

    typedef vector<FIELD> FIELDS; //所有列的欄位結構體集合
    typedef vector<string> ROW;  //每一行儲存值

private:
    vector<ROW> rows_; // 總共儲存多個行
    FIELDS fields_;
};

class MysqlDB
{
public:
    MysqlDB();
    ~MysqlDB();
    void Open(const char* host,
        const char* user,
        const char* passwd,
        const char* db,
        unsigned int port);
    void Close();

    unsigned long long ExecSQL(const char* sql);
    MysqlRecordset QuerySQL(const char* sql);

    unsigned long long GetInsertId() const;
    void StartTransaction();
    void Commit();
    void Rollback();


private:
    MYSQL* mysql_;
};

}

#endif // _MYSQL_DB_H_

MysqlDB.cpp:
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <exception>
#include "MysqlDB.h"

using namespace std;
using namespace DAL;

MysqlDB::MysqlDB() : mysql_(NULL)
{
}

MysqlDB::~MysqlDB()
{
    if (mysql_)
    {
        Close();
    }
}
void MysqlDB::Open(const char* host,
                   const char* user,
                   const char* passwd,
                   const char* db,
                   unsigned int port)
{

    mysql_ = mysql_init(NULL);
    if (mysql_ == NULL)
    {
        string errmsg = mysql_error(mysql_);
        throw Exception("DB ERROR:"+errmsg);
    }

    my_bool reconnect = true;
    mysql_options(mysql_, MYSQL_OPT_RECONNECT, &reconnect);
    mysql_options(mysql_, MYSQL_SET_CHARSET_NAME, "gbk");

    if (!mysql_real_connect(mysql_, host, user,
        passwd, db, 0NULL0))
    {
        string errmsg = mysql_error(mysql_);
        Close();
        throw Exception("DB ERROR:"+errmsg);
    }
}

void MysqlDB::Close()
{
    if (NULL != mysql_)
    {
        mysql_close(mysql_);
        mysql_ = NULL;
    }
}

MysqlRecordset MysqlDB::QuerySQL(const char* sql)
{
    if (mysql_query(mysql_, sql) != 0)
    {
        //int errno = mysql_errno(mysql_);
        string errmsg = mysql_error(mysql_);
        throw Exception("DB ERROR:"+errmsg);
    }

    MYSQL_RES*  mysql_res;
    mysql_res = mysql_store_result(mysql_);

    //得到查詢返回的行數
    //unsigned long n = mysql_affected_rows(mysql_);    

    //指向  mysql 的查詢欄位集
    MYSQL_FIELD* mysql_field = NULL;
    
    MysqlRecordset rs;
    unsigned int i = 0;
    unsigned int nCols = mysql_num_fields(mysql_res);
    while ((mysql_field = mysql_fetch_field(mysql_res)) != NULL)
    {
        MysqlRecordset::FIELD field;
        field.name = mysql_field->name;
        field.index = i;
        ++i;
        rs.fields_.push_back(field); //壓入某個列欄位的結構體
    }
 
    MYSQL_ROW mysql_row;
    while ((mysql_row = mysql_fetch_row(mysql_res)))
    {
        MysqlRecordset::ROW row(nCols);
        for (unsigned int i = 0; i< nCols; ++i)
        {
            row[i] = mysql_row[i] ? mysql_row[i] : "";
        }
        rs.rows_.push_back(row); //壓入某一行的儲存值
        
    }
    

    mysql_free_result(mysql_res);

    return rs;

}

unsigned long long MysqlDB::ExecSQL(const char* sql)
{
    if (mysql_query(mysql_, sql) != 0)
    {
        //int errno = mysql_errno(mysql_);
        string errmsg = mysql_error(mysql_);
        throw Exception("DB ERROR:"+errmsg);
    }

    return mysql_affected_rows(mysql_);

}

void MysqlDB::StartTransaction()
{
    if (mysql_query(mysql_, "START TRANSACTION") != 0)
    {
        //int errno = mysql_errno(mysql_);
        string errmsg = mysql_error(mysql_);
        throw Exception("DB ERROR:"+errmsg);
    }
}

void MysqlDB::Commit()
{
    if (mysql_query( mysql_, "COMMIT") != 0)
    {
        //int errno = mysql_errno(mysql_);
        string errmsg = mysql_error(mysql_);
        throw Exception("DB ERROR:"+errmsg);
    }
}

void MysqlDB::Rollback()
{
    if (mysql_query(mysql_, "ROLLBACK") == 0)
    {
        //int errno = mysql_errno(mysql_);
        string errmsg = mysql_error(mysql_);
        throw Exception("DB ERROR:"+errmsg);
    }
}


unsigned long long MysqlDB::GetInsertId() const
{
    return mysql_insert_id(mysql_);  //auto_increment欄位
}

具體使用方法就很簡單了,包含MysqlDB.h,比如 
MysqlDB mysqldb;
mysqldb.open(...);
mysqldb.QuerySQL(...);
...

參考:

資料庫系統概論

mysql 5.1 參考手冊



相關文章