#ifndef _SMART_DB_H
#define _SMART_DB_H
#include "sqlite3.h"
#include <string>
#include <iostream>
#include <vector>
/*
* function:封装的sqlite类,具备链接,查询,关闭功能
* des:sql用字符串拼接方式,会有sql注入的风险
*/
class SmartDB
{
public:
SmartDB();
/*
* @function: 创建或打开数据库,如果数据库不存在,
* 则数据库将被创建并打开,如果创建失败则设置失败标志
* @param[in] fileName: 数据库文件的位置
*/
SmartDB(const std::string &fileName);
/*
* @des: 析构函数, 释放资源,关闭数据库
*/
~SmartDB();
/*
* @function: 打开数据库
* @param[in] fileName: 数据库文件的位置
* @return bool: 成功打开数据库true, 否则false
*/
bool Open(const std::string &fileName);
/*
* @function: 释放资源,关闭数据库
* @return bool: 成功关闭数据库true, 否则false
*/
bool Close();
/*
* @function: 得到最后一次错误码
* @return int: 返回最近一次错误码
*/
int GetLastErrorCode();
/*
* @function: 解析和保存sql语句
* @des: 不许用拼接字符串,因为有sql注入的安全问题
* @param[in] strSql: 需要执行的sql语句, 可能带占位符?
* @return bool: 成功返回true, 否则false
*/
bool Prepare(const std::string& strSql);
/*
* @function: 绑定SQL语句预编译时把一些参数使用占位符(这里是?号)来代替
* @param[in] current: 占位符的索引
* @param[in] strData: 占位符问号的具体内容
*/
void BindValue(int current, const std::string &strData);
/*
* @function: 执行sql, 返回函数执行的一个值,执行简单的汇聚函数,如select cout(*), select max(*)等
* @param[in] strSql: sql语句,有可能占位符"?"
* @param[in] strArgs: 参数列表,用来填充占位符, 变参
* @param[out] vecData: 查询出来的全部数据
* @return int: 最近一次错误码
*/
int ExecuteScalar(const std::string &strSql, std::vector<std::vector<std::string>>& vecData, const int num, const std::string strFirst, ...);
private:
/*
* @function: 将单行所有列数据插入vector中
* @param[in] iCount: 单行列数
* @param[out] vecData: 单行数据集
*/
void InsertLine(std::vector<std::string>& vecData, const int& iCount);
/*
* @function: 关闭sqlite句柄
* @return int: 返回最近一次错误码
*/
int CloseDBHandle();
private:
sqlite3 *m_dbHandle = NULL; // sqlite3数据库句柄
sqlite3_stmt *m_statement = NULL; // 一条SQL语句的实例
int m_code; // 记录最近一次的错误码
};
#endif
#include "smartdb.h"
#include <stdarg.h>
SmartDB::SmartDB()
{
}
/*
* @function: 创建或打开数据库,如果数据库不存在,
* 则数据库将被创建并打开,如果创建失败则设置失败标志
* @param[in] fileName: 数据库文件的位置
*/
SmartDB::SmartDB(const std::string &fileName)
{
this->Open(fileName);
}
/*
* @des: 析构函数, 释放资源,关闭数据库
*/
SmartDB::~SmartDB()
{
this->Close();
}
/*
* @function: 打开数据库
* @param[in] fileName: 数据库文件的位置
* @return bool: 成功打开数据库true, 否则false
*/
bool SmartDB::Open(const std::string &fileName)
{
// 打开对应fileName的sqlie数据库
this->m_code = sqlite3_open(fileName.data(), &m_dbHandle);
return (SQLITE_OK == this->m_code); // 是否正常打开
}
/*
* @function: 关闭sqlite句柄
* @return int: 返回最近一次错误码
*/
int SmartDB::CloseDBHandle()
{
this->m_code = sqlite3_close(this->m_dbHandle);
while (this->m_code == SQLITE_BUSY) // 如果sqlite状态繁忙
{
this->m_code = SQLITE_OK;
// 循环取得sql语句实例
sqlite3_stmt *stmt = sqlite3_next_stmt(this->m_dbHandle, NULL);
if (stmt == NULL)
{
break;
}
// 销毁sql语句实例,防止内存泄漏
this->m_code = sqlite3_finalize(stmt);
if (this->m_code == SQLITE_OK) // 成功销毁
{
// 关闭sqlite句柄
this->m_code = sqlite3_close(this->m_dbHandle);
}
}
return this->m_code;
}
/*
* @function: 释放资源,关闭数据库
* @return bool: 成功关闭数据库true, 否则false
*/
bool SmartDB::Close()
{
if (this->m_dbHandle == NULL)
{
return true;
}
sqlite3_finalize(this->m_statement); // 销毁sql语句实例,防止内存泄漏
this->m_code = this->CloseDBHandle(); // 关闭sqlite句柄
this->m_statement = nullptr;
this->m_dbHandle = nullptr;
return (SQLITE_OK == this->m_code); // 是否正常关闭
}
/*
* @function: 得到最后一次错误码
* @return int: 返回最近一次错误码
*/
int SmartDB::GetLastErrorCode()
{
return this->m_code;
}
/*
* @function: 解析和保存sql语句
* @des: 不许用拼接字符串,因为有sql注入的安全问题
* @param[in] strSql: 需要执行的sql语句, 可能带占位符?
* @return bool: 成功返回true, 否则false
*/
bool SmartDB::Prepare(const std::string& strSql)
{
// 执行sql脚本语句
this->m_code = sqlite3_prepare_v2(this->m_dbHandle, strSql.data(), strlen(strSql.data()), &this->m_statement, NULL);
if (m_code != SQLITE_OK)
{
return false;
}
return true;
}
/*
* @function: 绑定SQL语句预编译时把一些参数使用占位符(这里是?号)来代替
* @param[in] current: 占位符的索引
* @param[in] strData: 占位符问号的具体内容
*/
void SmartDB::BindValue(int current, const std::string &strData)
{
// 绑定参数
this->m_code = sqlite3_bind_text(this->m_statement, current, strData.data(), strlen(strData.data()), NULL);
}
/*
* @function: 执行sql, 返回函数执行的一个值,执行简单的汇聚函数,如select cout(*), select max(*)等
* @param[in] strSql: sql语句,有可能占位符"?"
* @param[in] strArgs: 参数列表,用来填充占位符, 变参
* @param[out] vecData: 查询出来的全部数据
* @return int: 最近一次错误码
*/
int SmartDB::ExecuteScalar(const std::string &strSql, std::vector<std::vector<std::string>>& vecData, const int num, const std::string strFirst, ...)
{
// 准备执行sql脚本语句
if (this->Prepare(strSql) == false)
{
return this->m_code;
}
if (num > 0) {
int current = 1;
BindValue(current, strFirst);
if (this->m_code != SQLITE_OK)
{
return this->m_code;
}
// 绑定参数
va_list ap;
va_start(ap, strFirst);
std::string strSrc = "";
for (int i = 1; i < num; ++i)
{
current += 1;
strSrc = va_arg(ap, const std::string);
BindValue(current, strSrc);
if (this->m_code != SQLITE_OK)
{
return this->m_code;
}
}
va_end(ap);
}
// 获取列数
int iCount = sqlite3_column_count(this->m_statement);
while (true)
{
// 执行sql语句,获取每行的数据
this->m_code = sqlite3_step(this->m_statement);
if (this->m_code == SQLITE_ROW)
{
// 插入每一列的值
std::vector<std::string> vecTmp;
this->InsertLine(vecTmp, iCount);
vecData.push_back(vecTmp);
}
else if (this->m_code == SQLITE_DONE) // 数据行都已经获取,跳出循环
{
break;
}
else // 出错
{
break;
}
}
// 重置一个准备语句对象到它的初始状态,然后准备被重新执行
sqlite3_reset(this->m_statement);
return this->m_code;
}
/*
* @function: 将单行数据插入vector中
* @param[in] iCount: 单行列数
* @param[out] vecData: 单行数据集
*/
void SmartDB::InsertLine(std::vector<std::string>& vecData, const int& iCount)
{
for (int i = 0; i < iCount; ++i)
{
// 这里需要先判断当前列的类型,列的类型不同,调用的api函数不同
// 获取实际的数据值
int coltype = sqlite3_column_type(this->m_statement, i);
if (coltype == SQLITE_TEXT)
{
const char* val = (const char*)sqlite3_column_text(this->m_statement, i);
vecData.push_back(std::string(val));
}
else if (coltype == SQLITE_NULL)
{
vecData.push_back(std::string(""));
}
std::cout << sqlite3_column_name(this->m_statement, i) << "\n";
}
}
因为sqlite是utf-8编码,需要转码,vs
#include "smartdb.h"
#include <vector>
#include <stdio.h>
#include <windows.h>
void ConvertGBKToUtf8(std::string& amp, std::string strGBK)
{
int len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)strGBK.c_str(), -1, NULL, 0);
unsigned short * wszUtf8 = new unsigned short[len + 1];
memset(wszUtf8, 0, len * 2 + 2);
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)strGBK.c_str(), -1, (LPWSTR)wszUtf8, len);
len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)wszUtf8, -1, NULL, 0, NULL, NULL);
char *szUtf8 = new char[len + 1];
memset(szUtf8, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)wszUtf8, -1, szUtf8, len, NULL, NULL);
//strGBK = szUtf8;
amp = szUtf8;
delete[] szUtf8;
delete[] wszUtf8;
}
void ConvertUtf8ToGBK(std::string&, std::string strUtf8)
{
int len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)strUtf8.c_str(), -1, NULL, 0);
unsigned short * wszGBK = new unsigned short[len + 1];
memset(wszGBK, 0, len * 2 + 2);
MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)strUtf8.c_str(), -1, (LPWSTR)wszGBK, len);
len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)wszGBK, -1, NULL, 0, NULL, NULL);
char *szGBK = new char[len + 1];
memset(szGBK, 0, len + 1);
WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)wszGBK, -1, szGBK, len, NULL, NULL);
//strUtf8 = szGBK;
amp = szGBK;
delete[] szGBK;
delete[] wszGBK;
}
int main()
{
SmartDB dB;
if (!dB.Open("FastFile.db"))
{
return 0;
}
std::string strSql = "select cn, funcname from typelanguage where funcname = ?;";
ConvertGBKToUtf8(strSql, strSql);
std::vector<std::vector<std::string>> vecDst;
std::string str = "car_mode";
ConvertGBKToUtf8(str, str);
std::string str2 = "1";
dB.ExecuteScalar(strSql, vecDst, 1, str);
for (int i = 0; i < vecDst.size(); ++i)
{
for (int j = 0; j < vecDst[i].size(); ++j)
{
std::string strDst = "";
ConvertUtf8ToGBK(strDst, vecDst[i][j]);
std::cout << strDst << "\n";
}
}
getchar();
}