网上的封装类说心里话,用的很不舒服。
不知道其他的C++程序员用的数据库封装都是什么样子,至少对我这种PHP过来的程序员来说,这种还需要完全自己写sql的数据库封装类用起来很痛苦。
所以,为了以后不痛苦,只能现在痛苦一下了。把网上的类重新改了下
DBUtil.h
//
// DBUtil.h
//
// Created by Ron on 15/8/25.
//
//
#ifndef __DBUtil__
#define __DBUtil__
#include "sqlite3.h"
#include "cocos2d.h"
USING_NS_CC;
class DBUtil {
private:
//数据库
sqlite3* m_pDataBase;
private:
#pragma mark <构造 && 析构>
DBUtil();
virtual ~DBUtil();
public :
#pragma mark <创建 && 销毁单例>
static DBUtil* getInstance();
static void destoryInstance();
#pragma mark <自定义数据库操作>
void resetParam();//重置操作数据
/**
* 创建表
*
* @param where where条件字符串
*/
void createTable(std::vector<std::string> param, std::string primaryName);
/**
* table表名
*
* @param where where条件字符串
*/
DBUtil* table(std::string tableName);
/**
* where条件
*
* @param where where条件字符串
*/
DBUtil* where(std::string where);
/**
* 插入数据
*
* @param param 要插入的数据
*/
int insert(std::map<std::string, std::string> param);
/**
* 查询,返回多个条件
*/
std::vector<std::map<std::string, std::string>> select();
/**
* 查询,返回一个条件
*/
std::map<std::string, std::string> find();
/**
* 查询,返回个数
*/
int count();
/**
* 更新数据
*
* @param param 要插入的数据
*/
int update(std::map<std::string, std::string> param);
/**
* 删除
*/
int del();
private:
std::string ron_tableName;
std::string ron_where;
public:
#pragma mark <数据库操作>
/**
* 打开数据库(创建)
*
* @param aDataBaseName 数据库名
*/
void openDBWithName();
/**
* 关闭数据库
*/
void closeDB();
/**
* 创建数据表
*
* @param aSql 建表sql语句
* @param aTableName 表名
*/
void createTable(std::string aSql, std::string aTableName);
/**
* 通过表名查询该表是否存在
*
* @param aTabelName 表秒
*
* @return true: 存在 false: 不存在
*/
bool isExistTableByName(std::string aTabelName);
/**
* 删除数据表
*
* @param aSql 删表sql语句
* @param aTableName 表名
*/
void deleteTable(std::string aSql, std::string aTableName);
/**
* 开始事务
*
* @return 操作结果(sqlite3提供的宏)
*/
int beginTransaction();
/**
* 提交事务(失败回滚)
*
* @param aResult 操作结果
*
* @return 操作结果(sqlite3提供的宏)
*/
int comitTransaction(int aResult);
};
#endif /* defined(__DBUtil__) */
DBUtil.cpp
//
// DBUtil.cpp
//
// Created by ron on 15/8/25.
//
//
#include "DBUtil.h"
static DBUtil* s_pInstance = NULL;
const std::string cDBName = "gamedb";
#pragma mark <构造 && 析构>
DBUtil::DBUtil():m_pDataBase(NULL),ron_where(""),ron_tableName("")
{
}
DBUtil::~DBUtil() {
}
#pragma mark <创建 && 销毁单例>
DBUtil* DBUtil::getInstance() {
if (!s_pInstance) {
s_pInstance = new DBUtil();
}
return s_pInstance;
}
void DBUtil::destoryInstance() {
delete s_pInstance;
s_pInstance = NULL;
}
#pragma mark <数据库操作>
/**
* 打开数据库(创建)
*
* @param aDataBaseName 数据库名
*/
void DBUtil::openDBWithName() {
std::string writeablePath = FileUtils::getInstance()->getWritablePath();
CCLOG("path=%s", writeablePath.c_str());
std::string dbPath = writeablePath + cDBName;
int result = sqlite3_open(dbPath.c_str(), &m_pDataBase);
char* errMsg = NULL;
if (result != SQLITE_OK) {
log("打开数据库失败,错误码:%d,错误原因:%s\n", result, errMsg);
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
}
}
/**
* 关闭数据库
*/
void DBUtil::closeDB() {
if (m_pDataBase) {
sqlite3_close(m_pDataBase);
m_pDataBase = NULL;
}
}
/**
* 创建数据表
*
* @param aSql 建表sql语句
* @param aTableName 表名
*
* @usage string sql = "create table user(id integer, username text, password text)";
*/
void DBUtil::createTable(std::string aSql, std::string aTableName) {
openDBWithName();
if (!isExistTableByName(aTableName)) {
char* errMsg = NULL;
int result = sqlite3_exec(m_pDataBase, aSql.c_str(), NULL, NULL, &errMsg);
if (result != SQLITE_OK) {
log("创建表失败,错误码:%d,错误原因:%s\n", result, errMsg);
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
}
}
closeDB();
}
/**
* 是否存在某张数据表的查询回调
*
* @return 0
*/
int isExistTableCallback(void* para, int n_column, char ** column_value, char ** column_name) {
bool *isExisted_= (bool*)para;
*isExisted_= (**column_value) != '0';
return 0;
}
/**
* 通过表名查询该表是否存在
*
* @param aTabelName 表秒
*
* @return true: 存在 false: 不存在
*/
bool DBUtil::isExistTableByName(std::string aTabelName) {
if (m_pDataBase) {
//判断表是否存在
bool isExist;
char* errMsg = NULL;
std::string sql = "select count(type) from sqlite_master where type = 'table' and name = '" + aTabelName + "'";
int result = sqlite3_exec(m_pDataBase, sql.c_str(), isExistTableCallback, &isExist, &errMsg);
if (result != SQLITE_OK) {
log("查询表是否存在失败,错误码:%d,错误原因:%s\n", result, errMsg);
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
}
return isExist;
}
return false;
}
/**
* 删除数据表
*
* @param aSql 删表sql语句
* @param aTableName 表名
*
* @usage string sql = "drop table name";
*/
void DBUtil::deleteTable(std::string aSql, std::string aTableName) {
openDBWithName();
beginTransaction();
int result = 0;
if (isExistTableByName(aTableName)) {
char* errMsg = NULL;
result = sqlite3_exec(m_pDataBase, aSql.c_str(), NULL, NULL, &errMsg);
if (result != SQLITE_OK) {
log("创建表失败,错误码:%d,错误原因:%s\n", result, errMsg);
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
}
}
comitTransaction(result);
closeDB();
}
/**
* 开始事务
*
* @return 操作结果(sqlite3提供的宏)
*/
int DBUtil::beginTransaction() {
char* errMsg = NULL;
int result = sqlite3_exec(m_pDataBase, "begin transaction", 0, 0, &errMsg);
if (result != SQLITE_OK ){
log("开始事务记录失败,错误码:%d,错误原因:%s\n", result, errMsg);
}
return result;
}
/**
* 提交事务(失败回滚)
*
* @param aResult 操作结果
*
* @return 操作结果(sqlite3提供的宏)
*/
int DBUtil::comitTransaction(int aResult) {
if (aResult == SQLITE_OK) {
char* errMsg = NULL;
int result = sqlite3_exec(m_pDataBase, "commit transaction", 0, 0, &errMsg);
if (result != SQLITE_OK) {
log("提交事务记录失败,错误码:%d,错误原因:%s\n" , result, errMsg);
}
return result;
} else {
char* errMsg = NULL;
int result = sqlite3_exec(m_pDataBase, "rollback transaction", 0, 0, &errMsg);
if (result != SQLITE_OK ) {
log("回滚事务记录失败,错误码:%d,错误原因:%s\n", result, errMsg);
}
return result;
}
}
#pragma mark 自定义数据库操作
DBUtil* DBUtil::table(std::string tableName)
{
ron_tableName = tableName;
return DBUtil::getInstance();
}
DBUtil* DBUtil::where(std::string where)
{
std::string str = " WHERE ";
ron_where = str.append(where);
return DBUtil::getInstance();
}
/**
* 重置操作数据
*/
void DBUtil::resetParam()
{
ron_tableName = "";
ron_where = "";
}
/**
* 查询回调
*
* @return 0
*/
int selectCallback(void* para, int n_column, char** column_value, char** column_name ) {
std::map<std::string, std::string> mapResults ;
for (int i = 0; i < n_column; i++) {
mapResults.insert(std::make_pair<std::string, std::string>((std::string)column_name[i], (std::string)column_value[i]));
}
std::vector<std::map<std::string, std::string> >* vect = (std::vector<std::map<std::string, std::string> >*)para;
vect->push_back(mapResults);
return 0;
}
std::vector<std::map<std::string, std::string>> DBUtil::select()
{
//vector是查询的结果集,每一个结果都存在map中
//map的第一string是key(字段名),第二个string是value(查询出的对应数据)
std::vector<std::map<std::string, std::string> > vec;
try {
if (ron_tableName.empty()) {
throw 0;//表名为空的话,则抛出异常
}
openDBWithName();
std::string sql = "SELECT * FROM ";
sql.append(ron_tableName);
sql.append(ron_where);
char* errMsg = NULL;
int result = sqlite3_exec(m_pDataBase, sql.c_str(), selectCallback, &vec, &errMsg);
if (result != SQLITE_OK) {
log("查询失败,错误码:%d,错误原因:%s\n", result, errMsg);
throw 0;
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
throw 0;
}
resetParam();
closeDB();
} catch (...) {
std::vector<std::map<std::string, std::string>> empty;
resetParam();
closeDB();
return empty;
}
return vec;
}
/**
* 查询回调
*
* @return 0
*/
int findCallback(void* para, int n_column, char** column_value, char** column_name ) {
std::map<std::string, std::string> mapResults ;
mapResults.insert(std::make_pair<std::string, std::string>((std::string)column_name[0], (std::string)column_value[0]));
for (int i = 0; i < n_column; i++) {
mapResults.insert(std::make_pair<std::string, std::string>((std::string)column_name[i], (std::string)column_value[i]));
}
std::map<std::string, std::string>* map = (std::map<std::string, std::string>*)para;
*map = mapResults;
return 0;
}
std::map<std::string, std::string> DBUtil::find()
{
//map的第一string是key(字段名),第二个string是value(查询出的对应数据)
std::map<std::string, std::string> map;
try {
if (ron_tableName.empty()) {
throw 0;//表名为空的话,则抛出异常
}
openDBWithName();
std::string sql = "SELECT * FROM ";
sql.append(ron_tableName);
sql.append(ron_where);
sql.append(" LIMIT 1");
char* errMsg = NULL;
int result = sqlite3_exec(m_pDataBase, sql.c_str(), findCallback, &map, &errMsg);
if (result != SQLITE_OK) {
log("查询失败,错误码:%d,错误原因:%s\n", result, errMsg);
throw 0;
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
throw 0;
}
resetParam();
closeDB();
} catch (...) {
resetParam();
closeDB();
std::map<std::string, std::string> empty;
return empty;
}
return map;
}
/**
* 查询数据条数回调
*
* @return 0
*/
int countCallback(void* para, int n_column, char** column_value, char** column_name) {
int* count = (int*)para;
*count = (int)atof(column_value[0]);
return 0;
}
/**
* 查询记录的条数
*
* @param sql 查询记录sql语句
*
* @return 记录条数
*/
int DBUtil::count() {
int count = 0;
try {
if (ron_tableName.empty()) {
throw 0;//表名为空的话,则抛出异常
}
openDBWithName();
std::string sql = "SELECT * FROM ";
sql.append(ron_tableName);
sql.append(ron_where);
char* errMsg = NULL;
int result = sqlite3_exec(m_pDataBase, sql.c_str(), countCallback, &count, &errMsg);
if (result != SQLITE_OK) {
log("查询失败,错误码:%d,错误原因:%s\n", result, errMsg);
throw 0;
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
throw 0;
}
resetParam();
closeDB();
} catch (...) {
resetParam();
closeDB();
return 0;
}
return count;
}
void DBUtil::createTable(std::vector<std::string> param, std::string primaryName)
{
try {
if (ron_tableName.empty()) {
throw 0;//表名为空的话,则抛出异常
}
openDBWithName();
std::string sql = "CREATE TABLE ";
sql.append(ron_tableName);
sql.append("(");
for (auto value : param) {
sql.append(value);
if (value == primaryName) {
sql.append(" INTEGER PRIMARY KEY AUTOINCREMENT");
}
sql.append(",");
}
sql.erase(sql.end()-1);
sql.append(")");
if (!isExistTableByName(ron_tableName)) {
char* errMsg = NULL;
int result = sqlite3_exec(m_pDataBase, sql.c_str(), NULL, NULL, &errMsg);
if (result != SQLITE_OK) {
log("创建表失败,错误码:%d,错误原因:%s\n", result, errMsg);
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
}
}
} catch (...) {
}
resetParam();
closeDB();
}
int DBUtil::insert(std::map<std::string, std::string> param)
{
int result = 0;
try {
if (ron_tableName.empty()) {
throw 0;//表名为空的话,则抛出异常
}
openDBWithName();
beginTransaction();
std::string sql = "INSERT INTO ";
sql.append(ron_tableName);
sql.append(" (");
for (std::map<std::string, std::string>::iterator i = param.begin(); i != param.end(); i++) {
sql.append(i->first);
sql.append(",");
}
sql.erase(sql.end()-1);
sql.append(") VALUES (");
for (std::map<std::string, std::string>::iterator i = param.begin(); i != param.end(); i++) {
sql.append("\"");
sql.append(i->second);
sql.append("\",");
}
sql.erase(sql.end()-1);
sql.append(");");
char* errMsg = NULL;
result = sqlite3_exec(m_pDataBase, sql.c_str(), NULL, NULL, &errMsg);
if (result != SQLITE_OK) {
log("插入记录失败,错误码:%d,错误原因:%s\n", result, errMsg );
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
}
comitTransaction(result);
} catch (...) {
result = 1;
}
resetParam();
closeDB();
return result;
}
int DBUtil::update(std::map<std::string, std::string> param)
{
int result = 0;
try {
if (ron_tableName.empty() || ron_where.empty()) {
throw 0;//表名为空或者where条件为空的话,则抛出异常
}
openDBWithName();
beginTransaction();
std::string sql = "UPDATE ";
sql.append(ron_tableName);
sql.append(" SET ");
for (std::map<std::string, std::string>::iterator i = param.begin(); i != param.end(); i++) {
sql.append(i->first);
sql.append("=\"");
sql.append(i->second);
sql.append("\",");
}
sql.erase(sql.end()-1);
sql.append(ron_where);
char* errMsg = NULL;
result = sqlite3_exec(m_pDataBase, sql.c_str(), NULL, NULL, &errMsg);
if (result != SQLITE_OK) {
log("更新记录失败,错误码:%d,错误原因:%s\n", result, errMsg );
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
}
comitTransaction(result);
} catch (...) {
result = 1;
}
resetParam();
closeDB();
return result;
}
int DBUtil::del()
{
int result = 0;
try {
if (ron_tableName.empty() || ron_where.empty()) {
throw 0;//表名为空或者where条件为空的话,则抛出异常
}
openDBWithName();
beginTransaction();
std::string sql = "DELETE FROM ";
sql.append(ron_tableName);
sql.append(ron_where);
char* errMsg = NULL;
result = sqlite3_exec(m_pDataBase, sql.c_str(), NULL, NULL, &errMsg);
if (result != SQLITE_OK) {
log("删除记录失败,错误码:%d,错误原因:%s\n", result, errMsg );
}
if (errMsg) {
sqlite3_free(errMsg);
errMsg = NULL;
}
comitTransaction(result);
} catch (...) {
result = 1;
}
resetParam();
closeDB();
return result;
}
用法也很简单
std::vector<std::string> param;
param.push_back("id");
param.push_back("name");
param.push_back("age");
DBUtil::getInstance()->table("rontab2")->createTable(param, "id");//建表
std::map<std::string, std::string> m;
m["name"] = "wahaha";
m["age"] = "年龄";
DBUtil::getInstance()->table("rontab3")->insert(m);//添加
auto data = DBUtil::getInstance()->table("rontab3")->select();//查找
DBUtil::getInstance()->where("id = 8")->table("rontab3")->update(m);//更新
DBUtil::getInstance()->where("id=3")->table("rontab3")->del();//删除
这种增删改查是不是简单到没朋友?
不过实话实说。缺陷还是不少。
首先,建表只能建无类型的,虽然sqlite会自动转换,但是由于我的insert和update的缺陷,导致,除了主键,其他都是字符串类型。
还有,代码里的string字符串连接确实有点坑爹了。真心对C++不太熟悉,图省事,就先这样了。
确实有很多可以优化的地方,但是,封装这样一个类真心对我来说太枯燥。我宁肯写10000行代码去开发游戏的逻辑,也不想写100行这种代码。所以,先这样吧,以后哪天心情好了,再重新优化一下吧。或者哪位兄弟无聊也可以为人类做下贡献:)