Mysql数据库学习(四):常用Mysql C API 介绍和使用、封装一个访问Mysql数据库的类MysqlDB

首先,环境是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

示例代码如下:

#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", 0, NULL, 0))
    {
        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:

#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:

#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, 0, NULL, 0))
    {
        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 参考手册

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户画像

struts2 文件上传

uploadPath是相对webroot的路径,即webroot下的路径,将文件上传至该文件夹下。

823
来自专栏听Allen瞎扯淡

Fetch Size 与 JDBC 内存管理

接触到 JDBC 的 Fetch Size 这个属性缘起一个性能问题,项目中需要将一个有千万级数据量的表中的记录导出到文件中去。按照正常的路数,先初始化连接;接...

1182
来自专栏乐沙弥的世界

Oracle 外部表

外部表只能在Oracle 9i 之后来使用。简单地说,外部表,是指不存在于数据库中的表。通过向Oracle提供描述外部表的元数据,我们

682
来自专栏乐沙弥的世界

PL/SQL --> 异常处理(Exception)

Exception是一种PL/SQL标识符,当运行的PL/SQL块出现错误或警告,则会触发异常处理。为了提高程序的健壮性,可以在PL/SQL块中引

741
来自专栏互联网开发者交流社区

数据库的总结

1314
来自专栏ASP.NET MVC5 后台权限管理系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统(89)-EF执行SQL语句与存储过程

EF上下文 DbContext包含了DataBase属性,里面有很多方法,但是实际我们只需要用到个方法

1703
来自专栏岑玉海

Hive Tunning(二)优化存储

接着上一章我们讲的hive的连接策略,现在我们讲一下hive的数据存储。 下面是hive支持的数据存储格式,有我们常见的文本,JSON,XML,这里我们主要...

3764
来自专栏偏前端工程师的驿站

MyBatis魔法堂:Insert操作详解(返回主键、批量插入)

一、前言                                      数据库操作怎能少了INSERT操作呢?下面记录MyBatis关于INSERT...

6838
来自专栏乐沙弥的世界

PL/SQL --> 游标

映射在结果集中某一行数据的具体位置,类似于C语言中的指针。即通过游标方式定位到结果集中某个特定的行,然后根据业务需求

672
来自专栏清风

原创哈希数据导出算法 原

1287

扫码关注云+社区