選擇官方c接口,實現Idb通用接口。具體的數據庫操做,主要由兩個函數ExecQuerySql和ExecNoneQuerySql來封裝,底層的操做,主要使用sqlite3_prepare_v2來實現。mysql
由於Sqlit3是文件型數據庫,因此用智能指針來保存打開數據庫的句柄,防止內存泄漏。c++
std::unique_ptr<sqlite3, Deleter> mSQLitePtr;
對應的釋放結構git
struct Deleter { void operator()(sqlite3* apSQLite) { const int ret = sqlite3_close(apSQLite); (void)ret; SQLITECPP_ASSERT(SQLITE_OK == ret, "database is locked"); }; };
Sqlit3Db(const char* apFilename, const int aFlags = OPEN_READWRITE, const int aBusyTimeoutMs = 0, const char* apVfs = nullptr) : mFilename(apFilename) { sqlite3* handle; const int ret = sqlite3_open_v2(apFilename, &handle, aFlags, apVfs); //打開數據庫句柄 mSQLitePtr.reset(handle); //保存到智能指針中 ... //錯誤處理,略 };
Rjson ExecQuerySql(string aQuery, vector<string> fields) { Rjson rs = Utils::MakeJsonObjectForFuncReturn(STSUCCESS); //默認返回成功,使用utils.h中的json組裝函數 sqlite3_stmt* stmt = NULL; sqlite3* handle = getHandle(); //取得打開的數據庫句柄 string u8Query = Utils::UnicodeToU8(aQuery); const int ret = sqlite3_prepare_v2(handle, u8Query.c_str(), static_cast<int>(u8Query.size()), &stmt, NULL); if (SQLITE_OK != ret) { string errmsg = sqlite3_errmsg(getHandle()); //取得錯誤信息,重置返回信息 rs.ExtendObject(Utils::MakeJsonObjectForFuncReturn(STDBOPERATEERR, errmsg)); } else { ... //處理獲取表字段名稱的sql語句,略 sqlite3_get_table(handle, aQueryLimit0.c_str(), &pRes, &nRow, &nCol, &pErr); for (int j = 0; j < nCol; j++) { string fs = *(pRes + j); if (find(fields.begin(), fields.end(), fs) == fields.end()) { fields.push_back(fs); //保存數據表字段名稱 } } ... vector<Rjson> arr; //存儲查詢結果集的json對象數組 while (sqlite3_step(stmt) == SQLITE_ROW) { Rjson al; for (int j = 0; j < nCol; j++) { string k = fields.at(j); int nType = sqlite3_column_type(stmt, j); //取得字段值的類型 if (nType == 1) { //SQLITE_INTEGER al.AddValueInt(k, sqlite3_column_int(stmt, j)); //數值類型處理 } else if (nType == 2) { //SQLITE_FLOAT } else if (nType == 3) { //SQLITE_TEXT 字符串類型處理 al.AddValueString(k, Utils::U8ToUnicode((char*)sqlite3_column_text(stmt, j))); } else if (nType == 4) { //SQLITE_BLOB } else if (nType == 5) { //SQLITE_NULL } //暫時只處理了數值與字符串,其它暫未用到 } arr.push_back(al); } if (arr.empty()) //結果集爲空,返回查詢空 rs.ExtendObject(Utils::MakeJsonObjectForFuncReturn(STQUERYEMPTY)); rs.AddValueObjectArray("data", arr); //增長結果集,類型爲數組 } sqlite3_finalize(stmt); cout << "SQL: " << aQuery << endl; return rs; }
Rjson ExecNoneQuerySql(string aQuery) { Rjson rs = Utils::MakeJsonObjectForFuncReturn(STSUCCESS); sqlite3_stmt* stmt = NULL; sqlite3* handle = getHandle(); string u8Query = Utils::UnicodeToU8(aQuery); const int ret = sqlite3_prepare_v2(handle, u8Query.c_str(), static_cast<int>(u8Query.size()), &stmt, NULL); if (SQLITE_OK != ret) { string errmsg = sqlite3_errmsg(getHandle()); rs.ExtendObject(Utils::MakeJsonObjectForFuncReturn(STDBOPERATEERR, errmsg)); } else { sqlite3_step(stmt); //只須要執行一次就好 } sqlite3_finalize(stmt); cout << "SQL: " << aQuery << endl; return rs; }
提取保留關鍵字,它們是fuzzy,sort,page,size,sum,count,group,完成排序、分頁、分組等特殊查詢操做。github
string fuzzy = params.GetStringValueAndRemove("fuzzy"); //精確匹配與模糊查詢切換開關 string sort = params.GetStringValueAndRemove("sort"); //排序 int page = atoi(params.GetStringValueAndRemove("page").c_str()); //分頁 int size = atoi(params.GetStringValueAndRemove("size").c_str()); //分頁大小 string sum = params.GetStringValueAndRemove("sum"); //字段求和 string count = params.GetStringValueAndRemove("count"); //字段統計 string group = params.GetStringValueAndRemove("group"); //分組
處理關鍵字 ins,lks,ors ,完成in查詢,多字段模糊與查詢,多字段精確或查詢。sql
if (k.compare("ins") == 0) { string c = ele.at(0); //ins參數處理,第一個是字段名,後面是多個查詢值 vector<string>(ele.begin() + 1, ele.end()).swap(ele); //拼接in查詢sql語句 whereExtra.append(c).append(" in ( ").append(Utils::GetVectorJoinStr(ele)).append(" )"); } else if (k.compare("lks") == 0 || k.compare("ors") == 0) { whereExtra.append(" ( "); for (size_t j = 0; j < ele.size(); j += 2) { //lks與ors參數處理,(字段,值)的重複 if (j > 0) { whereExtra.append(" or "); } whereExtra.append(ele.at(j)).append(" "); //拼接sql語句 string eqStr = k.compare("lks") == 0 ? " like '" : " = '"; string vsStr = ele.at(j + 1); if (k.compare("lks") == 0) { vsStr.insert(0, "%"); vsStr.append("%"); } vsStr.append("'"); whereExtra.append(eqStr).append(vsStr); } whereExtra.append(" ) "); }
處理值,不等操做是在值中加入了不等符號;fuzzy開關。數據庫
if (Utils::FindStartsCharArray(QUERY_UNEQ_OPERS, (char*)v.c_str())) { vector<string> vls = Utils::MakeVectorInitFromString(v); if (vls.size() == 2) { //一個不等條件處理 where.append(k).append(vls.at(0)).append("'").append(vls.at(1)).append("'"); } else if (vls.size() == 4) { //一對不等條件處理 where.append(k).append(vls.at(0)).append("'").append(vls.at(1)).append("' and "); where.append(k).append(vls.at(2)).append("'").append(vls.at(3)).append("'"); } } else if (!fuzzy.empty() && vType == kStringType) { //精確查詢與模糊查詢切換 where.append(k).append(" like '%").append(v).append("%'"); } else { if (vType == kNumberType) //數值類型不加單引號 where.append(k).append(" = ").append(v); else //字符類型要加單引號 where.append(k).append(" = '").append(v).append("'"); }
分頁處理json
if (page > 0) { page--; querySql.append(" limit ").append(Utils::IntTransToString(page * size)).append(",").append(Utils::IntTransToString(size)); }
多值插入,sqlit3採用標準sql語法,insert into users (field1,field2) select 'val1','val2' union all select 'val3','val4' union all select ...api
Rjson insertBatch(string tablename, vector<Rjson> elements) { string sql = "insert into "; string keyStr = " ("; keyStr.append(Utils::GetVectorJoinStr(elements[0].GetAllKeys())).append(" ) "); //拼接表字段 for (size_t i = 0; i < elements.size(); i++) { vector<string> keys = elements[i].GetAllKeys(); string valueStr = " select "; for (size_t j = 0; j < keys.size(); j++) { //組裝一條紀錄 valueStr.append("'").append(elements[i][keys[j]]).append("'"); if (j < keys.size() - 1) { valueStr.append(","); } } if (i < elements.size() - 1) { //準備拼接下一條紀錄 valueStr.append(" union all "); } keyStr.append(valueStr); } sql.append(tablename).append(keyStr); return ExecNoneQuerySql(sql); //調用無結果集操做 }
Rjson transGo(vector<string> sqls, bool isAsync = false) { char* zErrMsg = 0; bool isExecSuccess = true; sqlite3_exec(getHandle(), "begin;", 0, 0, &zErrMsg); //開始事務處理 for (size_t i = 0; i < sqls.size(); i++) { string u8Query = Utils::UnicodeToU8(sqls[i]); //處理中文 int rc = sqlite3_exec(getHandle(), u8Query.c_str(), 0, 0, &zErrMsg); //處理一個操做 if (rc != SQLITE_OK) { isExecSuccess = false; cout << "Transaction Fail, sql " << i + 1 << " is wrong. Error: " << zErrMsg << endl; sqlite3_free(zErrMsg); break; } } if (isExecSuccess) //成功,提交到數據庫 { sqlite3_exec(getHandle(), "commit;", 0, 0, 0); sqlite3_close(getHandle()); cout << "Transaction Success: run " << sqls.size() << " sqls." << endl; return Utils::MakeJsonObjectForFuncReturn(STSUCCESS, "insertBatch success."); } else //有失敗的,回滾 { sqlite3_exec(getHandle(), "rollback;", 0, 0, 0); sqlite3_close(getHandle()); return Utils::MakeJsonObjectForFuncReturn(STDBOPERATEERR, zErrMsg); } }
https://github.com/zhoutk/Jorm
批量插入的標準sql居然很陌生,平時被mysql的方言慣壞了...數組