1.C++连接和操作MySQL的方式
系列文章:
MySQL 设计和命令行模式下建立详解
C++利用MySQL API连接和操作数据库实例详解
在Windows平台,我们可以使用ADO、ODBC或者MySQL API进行连接和操作。ADO (ActiveX Data Objects,ActiveX数据对象)是Microsoft提出的一个用于存取数据源的COM组件。它提供了程序语言和统一数据访问方式OLE DB的一个中间层,也就是Microsoft提出的应用程序接口(API)用以实现访问关系或非关系数据库中的数据。
ODBC(Open DataBase Connection)开放式系统互连,是一种数据库访问协议,提供了访问数据库的API接口。基于ODBC的应用程序,对数据库操作不依赖于具体的DBMS,不直接与DBMS打交道,所有数据库操作由对应DBMS的ODBC驱动程序完成,即:系统中不需要安装DBMS系统,如SQL SERVER 2005,但必须有SQL SERVER 2005的ODBC驱动程序,然后在ODBC管理器中注册数据源后,就可以在应用程序中通过ODBC API访问该数据库。ODBC数据库访问技术只适用于windows系统,因为需要在ODBC驱动程序管理器中进行数据源注册,而只有windows才集成了ODBC驱动程序管理器(“控制面板/管理工具/数据源”)。
ADO具有跨系统平台特性,它直接对DBMS数据库进行操作,即系统中必须有DBMS,但不需要驱动程序,不需要注册数据源,所以具有很好的可移植性。
那么,在Linux平台如何连接和使用MSQL数据库呢?我们同样可以使用ADO、unixODBC或者MySQL API。这里不再赘述前两者的用法,读者可自行研究实践,下文将详细讲解MySQL创建数据库和C++利用MSQL API连接和操作数据库。
2.MSQL数据库的设计和建立
MySQL数据库管理系统(DBMS)中,包含的MySQL中定义数据字段的类型对你数据库的优化是非常重要的。MySQL支持多种类型,大致可以分为三类:数值、日期/时间和字符串(字符)类型。
本文以大学熟悉的学生选课管理系统中用到的数据库为例,来实现对数据库的访问。本文数据库的建立,是在Linux平台使用msyql命令完成
主要有三张表:学生表,课程表和选课表。下面是数据表的详细情况。
学生表:
课程表:
选课表:
3.MSQL数据库的连接和操作
下面将讲解利用MySQL API来编写我们自己的用于访问MySQL的中间件,也是我们自己的组件。我们的组件在应用程序和MySQL数据库之间构成的层次结构如下图所示:
下面就来设计和实现我们自己的C++访问MySQL数据库的组件。
3.1头文件的设计
//mysqlhelper.h #ifndef __MYSQL_HELPER_H__ #define __MYSQL_HELPER_H__ #include <stdlib.h> #include <map> #include <vector> #include <string> using namespace std; #include <mysql.h> namespace mysqlhelper { /********************* *@brief 数据库异常类 **********************/ struct MysqlHelper_Exception //: public TC_Exception { MysqlHelper_Exception(const string &sBuffer):errorInfo(sBuffer){}; //: TC_Exception(sBuffer){}; ~MysqlHelper_Exception() throw(){}; string errorInfo; }; /*********************** * @brief 数据库配置接口 ***********************/ struct DBConf { string _host;//主机地址 string _user; //用户名 string _password;//密码 string _database; //数据库 string _charset; //字符集 int _port;//端口 int _flag; //客户端标识 /***************** * @brief 构造函数 *****************/ DBConf():_port(0), _flag(0){} /********************************** * @brief 读取数据库配置. * @param mpParam 存放数据库配置的map * dbhost: 主机地址 * dbuser:用户名 * dbpass:密码 * dbname:数据库名称 * dbport:端口 **********************************/ void loadFromMap(const map<string, string> &mpParam) { map<string, string> mpTmp = mpParam; _host = mpTmp["dbhost"]; _user = mpTmp["dbuser"]; _password = mpTmp["dbpass"]; _database = mpTmp["dbname"]; _charset = mpTmp["charset"]; _port = atoi(mpTmp["dbport"].c_str()); _flag = 0; if(mpTmp["dbport"] == "") { _port = 3306; } } }; /************************************************************** * @brief:MySQL数据库操作类 * @feature:非线程安全,通常一个线程一个MysqlHelper对象; * 对于insert/update可以有更好的函数封装,保证SQL注入; * MysqlHelper::DB_INT表示组装sql语句时,不加””和转义; * MysqlHelper::DB_STR表示组装sql语句时,加””并转义; **************************************************************/ class MysqlHelper{ public: /** * @brief 构造函数 */ MysqlHelper(); /** * @brief 构造函数. * @param: sHost:主机IP * @param sUser 用户 * @param sPasswd 密码 * @param sDatebase 数据库 * @param port 端口 * @param iUnixSocket socket * @param iFlag 客户端标识 */ MysqlHelper(const string& sHost, const string& sUser = "", const string& sPasswd = "", const string& sDatabase = "", const string &sCharSet = "", int port = 0, int iFlag = 0); /** * @brief 构造函数. * @param tcDBConf 数据库配置 */ MysqlHelper(const DBConf& tcDBConf); /** * @brief 析构函数. */ ~MysqlHelper(); /** * @brief 初始化. * * @param sHost 主机IP * @param sUser 用户 * @param sPasswd 密码 * @param sDatebase 数据库 * @param port 端口 * @param iUnixSocket socket * @param iFlag 客户端标识 * @return 无 */ void init(const string& sHost, const string& sUser = "", const string& sPasswd = "", const string& sDatabase = "", const string &sCharSet = "", int port = 0, int iFlag = 0); /** * @brief 初始化. * * @param tcDBConf 数据库配置 */ void init(const DBConf& tcDBConf); /** * @brief 连接数据库. * * @throws MysqlHelper_Exception * @return 无 */ void connect(); /** * @brief 断开数据库连接. * @return 无 */ void disconnect(); /** * @brief 获取数据库变量. * @return 数据库变量 */ string getVariables(const string &sName); /** * @brief 直接获取数据库指针. * * @return MYSQL* 数据库指针 */ MYSQL *getMysql(); /** * @brief 字符转义. * * @param sFrom 源字符串 * @param sTo 输出字符串 * @return 输出字符串 */ string escapeString(const string& sFrom); /** * @brief 更新或者插入数据. * * @param sSql sql语句 * @throws MysqlHelper_Exception * @return */ void execute(const string& sSql); /** * @brief mysql的一条记录 */ class MysqlRecord { public: /** * @brief 构造函数. * * @param record */ MysqlRecord(const map<string, string> &record); /** * @brief 获取数据,s一般是指数据表的某个字段名 * @param s 要获取的字段 * @return 符合查询条件的记录的s字段名 */ const string& operator[](const string &s); protected: const map<string, string> &_record; }; /** * @brief 查询出来的mysql数据 */ class MysqlData { public: /** * @brief 所有数据. * * @return vector<map<string,string>>& */ vector<map<string, string> >& data(); /** * 数据的记录条数 * * @return size_t */ size_t size(); /** * @brief 获取某一条记录. * * @param i 要获取第几条记录 * @return MysqlRecord类型的数据,可以根据字段获取相关信息, */ MysqlRecord operator[](size_t i); protected: vector<map<string, string> > _data; }; /** * @brief Query Record. * * @param sSql sql语句 * @throws MysqlHelper_Exception * @return MysqlData类型的数据,可以根据字段获取相关信息 */ MysqlData queryRecord(const string& sSql); /** * @brief 定义字段类型, * DB_INT:数字类型 * DB_STR:字符串类型 */ enum FT { DB_INT, DB_STR, }; /** * 数据记录 */ typedef map<string, pair<FT, string> > RECORD_DATA; /** * @brief 更新记录. * * @param sTableName 表名 * @param m