寫一套OA系統,為了方便進行數據庫操作,特意抽出一周的時間來研究C/C++訪問各種數據庫的方法,並打算封裝一套數據庫操作類,現在奉上最簡單的一部分:在Linux下訪問MySQL數據庫。
本文中使用的MySQL API代碼為C語言,如果各位對C++有興趣,可以考慮使用mysql++。
一、配置開發環境
首先需要編譯、安裝MySQL,安裝完成後,將MySQL目錄中的lib目錄添加到環境變量中。
新建C/C++工程,把$MYSQL_ROOT/include添加到編譯環境的包含路徑下面。在編譯選項中,增加$MYSQL_ROOT/lib目錄。在Link選項中增加-lmysqlclient(已經把lib目錄增加到系統環境變量中),或者直接引用libmysqlclient.so文件。
二、程序代碼
不多說了,直接上代碼,注釋都很詳細。
/*
* MySQLManager.h
*
* Created on: Feb 18, 2009
* Author: Steven Wee
*/
#ifndef MYSQLMANAGER_H_
#define MYSQLMANAGER_H_
#include "../Common/CheckStringTools.h"
#include <mysql.h>
#include <string>
#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
class MySQLManager
{
public:
/*
* Init MySQL
* @param hosts: Host IP address
* @param userName: Login UserName
* @param password: Login Password
* @param dbName: Database Name
* @param port: Host listen port number
*/
MySQLManager(std::string hosts, std::string userName, std::string password, std::string dbName, unsigned int port);
~MySQLManager();
void initConnection();
/*
* Making query from database
* @param mysql: MySQL Object
* @param sql: Running SQL command
*/
bool runSQLCommand(std::string sql);
/**
* Destroy MySQL object
* @param mysql MySQL object
*/
void destroyConnection();
bool getConnectionStatus();
vector< vector<string> > getResult();
protected:
void setUserName(std::string userName);
void setHosts(std::string hosts);
void setPassword(std::string password);
void setDBName(std::string dbName);
void setPort(unsigned int port);
private:
bool IsConnected;
vector< vector<string> > resultList;
MYSQL mySQLClient;
unsigned int DEFAULTPORT;
char * HOSTS;
char * USERNAME;
char * PASSWORD;
char * DBNAME;
};
#endif /* MYSQLMANAGER_H_ */
/*
* MySQLManager.cpp
*
* Created on: Feb 18, 2009
* Author: Steven Wee
*/
#include "MySQLManager.h"
MySQLManager::MySQLManager(string hosts, string userName, string password, string dbName, unsigned int port)
{
IsConnected = false;
this ->setHosts(hosts); // 設置主機IP地址
this ->setUserName(userName); // 設置登錄用戶名
this ->setPassword(password); // 設置登錄密碼
this ->setDBName(dbName); // 設置數據庫名
this ->setPort(port); // 設置端口號
}
MySQLManager::~MySQLManager()
{
this ->destroyConnection();
}
void MySQLManager::setDBName(string dbName)
{
if ( dbName.empty() )
{// 用戶沒有指定數據庫名
std::cout << "DBName is null! Used default value: mysql" << std::endl;
this ->DBNAME = new char[5];
strcpy(this ->DBNAME, "mysql");
}
else
{
this ->DBNAME = new char[dbName.length()];
strcpy(this ->DBNAME, dbName.c_str());
}
}
void MySQLManager::setHosts(string hosts)
{
if ( hosts.empty() )
{// 用戶沒有指定數據庫IP地址
std::cout << "Hosts is null! Used default value: localhost" << std::endl;
this ->HOSTS = new char[9];
strcpy(this ->HOSTS, "localhost");
}
else
{
this ->HOSTS = new char[hosts.length()];
strcpy(this ->HOSTS, hosts.c_str());
}
}
void MySQLManager::setPassword(string password)
{// 用戶沒有指定密碼
if ( password.empty() )
{
std::cout << "Password is null! Used default value: " << std::endl;
this ->PASSWORD = new char[1];
strcpy(this ->PASSWORD, "");
}
else
{
this ->PASSWORD = new char[password.length()];
strcpy(this ->PASSWORD, password.c_str());
}
}
void MySQLManager::setPort(unsigned int port)
{// 用戶沒有指定端口號,使用默認端口號
if ( port )
{
std::cout << "Port number is null! Used default value: 0" << std::endl;
this ->DEFAULTPORT = 0;
}
else
{
this ->DEFAULTPORT = port;
}
}
void MySQLManager::setUserName(string userName)
{// 用戶沒有指定登錄用戶名
if ( userName.empty() )
{
std::cout << "UserName is null! Used default value: root" << std::endl;
this ->USERNAME = new char[4];
strcpy(this ->USERNAME, "root");
}
else
{
this ->USERNAME = new char[userName.length()];
strcpy(this ->USERNAME, userName.c_str());
}
}
void MySQLManager::initConnection()
{
if ( IsConnected )
{// 已經連接到服務器
std::cout << "Is connected to server!" <<std::endl;
return;
}
mysql_init(&mySQLClient);// 初始化相關對象
if ( !mysql_real_connect( &mySQLClient, HOSTS, USERNAME, PASSWORD, DBNAME, DEFAULTPORT, NULL, 0) )
{// 連接到服務器
std::cout << "Error connection to database: %s\n" << mysql_error(&mySQLClient) << std::endl;
}
IsConnected = true;// 修改連接標識
}
bool MySQLManager::runSQLCommand(string sql)
{
if ( !IsConnected )
{// 沒有連接到服務器
std::cout << "Not connect to database!" << std::endl;
return false;
}
if ( sql.empty() )
{// SQL語句為空
std::cout << "SQL is null!" << std::endl;
return false;
}
MYSQL_RES *res;
MYSQL_ROW row;
unsigned int i,j = 0;
StringTools stringTools;
sql = stringTools.filterString(sql);
i = mysql_real_query(&mySQLClient,sql.c_str(),(unsigned int)strlen(sql.c_str()));// 執行查詢
if ( i )
{
std::cout << "Error query from database: %s\n" << mysql_error(&mySQLClient) << std::endl;
return false;
}
res = mysql_store_result(&mySQLClient);
vector<string> objectValue;
while( (row = mysql_fetch_row(res)) )
{// 遍歷結果集
objectValue.clear();
for ( j = 0 ; j < mysql_num_fields(res) ; j++ )
{
objectValue.push_back(row[j]);
}
this ->resultList.push_back(objectValue);
}
mysql_free_result(res); //free result after you get the result
return true;
}
vector< vector<string> > MySQLManager::getResult()
{
return resultList;
}
void MySQLManager::destroyConnection()
{
mysql_close(&mySQLClient);
this ->IsConnected = false;
}
bool MySQLManager::getConnectionStatus()
{
return IsConnected;
}
三、修改建議
本人在以後的完善中,打算把runSQLCommand(char * sql)函數分解成兩個或者三個函數,分別執行select和insert等語句。
在程序中,我並沒有強制要求參數必須為const,可能會出現一些安全問題。
本文僅起拋磚引玉的作用,希望有高手可以指點我程序中的問題。