SqlConnection.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
  3. *
  4. * This file is part of ZLToolKit(https://github.com/xia-chu/ZLToolKit).
  5. *
  6. * Use of this source code is governed by MIT license that can be found in the
  7. * LICENSE file in the root of the source tree. All contributing project authors
  8. * may be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #ifndef SQL_SQLCONNECTION_H_
  11. #define SQL_SQLCONNECTION_H_
  12. #include <stdio.h>
  13. #include <stdarg.h>
  14. #include <string.h>
  15. #include <string>
  16. #include <vector>
  17. #include <list>
  18. #include <deque>
  19. #include <sstream>
  20. #include <iostream>
  21. #include <stdexcept>
  22. #include "Util/logger.h"
  23. #include "Util/util.h"
  24. #if defined(_WIN32)
  25. #include <mysql.h>
  26. #pragma comment (lib,"libmysql")
  27. #else
  28. #include <mysql/mysql.h>
  29. #endif // defined(_WIN32)
  30. using namespace std;
  31. namespace toolkit {
  32. /**
  33. * 数据库异常类
  34. */
  35. class SqlException : public exception {
  36. public:
  37. SqlException(const string &sql,const string &err){
  38. _sql = sql;
  39. _err = err;
  40. }
  41. virtual const char* what() const noexcept {
  42. return _err.data();
  43. }
  44. const string &getSql() const{
  45. return _sql;
  46. }
  47. private:
  48. string _sql;
  49. string _err;
  50. };
  51. /**
  52. * mysql连接
  53. */
  54. class SqlConnection {
  55. public:
  56. /**
  57. * 构造函数
  58. * @param url 数据库地址
  59. * @param port 数据库端口号
  60. * @param dbname 数据库名
  61. * @param username 用户名
  62. * @param password 用户密码
  63. * @param character 字符集
  64. */
  65. SqlConnection(const string &url, unsigned short port,
  66. const string &dbname, const string &username,
  67. const string &password, const string &character = "utf8mb4") {
  68. mysql_init(&_sql);
  69. unsigned int timeout = 3;
  70. mysql_options(&_sql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
  71. if (!mysql_real_connect(&_sql, url.data(), username.data(),
  72. password.data(), dbname.data(), port, NULL, 0)) {
  73. mysql_close(&_sql);
  74. throw SqlException("mysql_real_connect",mysql_error(&_sql));
  75. }
  76. //兼容bool与my_bool
  77. uint32_t reconnect = 0x01010101;
  78. mysql_options(&_sql, MYSQL_OPT_RECONNECT, &reconnect);
  79. mysql_set_character_set(&_sql, character.data());
  80. }
  81. ~SqlConnection(){
  82. mysql_close(&_sql);
  83. }
  84. /**
  85. * 以printf样式执行sql,无数据返回
  86. * @param rowId insert时的插入rowid
  87. * @param fmt printf类型fmt
  88. * @param arg 可变参数列表
  89. * @return 影响行数
  90. */
  91. template<typename Fmt,typename ...Args>
  92. int64_t query(int64_t &rowId, Fmt &&fmt, Args && ...arg) {
  93. check();
  94. auto tmp = queryString(std::forward<Fmt>(fmt), std::forward<Args>(arg)...);
  95. if (doQuery(tmp)) {
  96. throw SqlException(tmp,mysql_error(&_sql));
  97. }
  98. rowId=mysql_insert_id(&_sql);
  99. return mysql_affected_rows(&_sql);
  100. }
  101. /**
  102. * 以printf样式执行sql,并且返回list类型的结果(不包含数据列名)
  103. * @param rowId insert时的插入rowid
  104. * @param ret 返回数据列表
  105. * @param fmt printf类型fmt
  106. * @param arg 可变参数列表
  107. * @return 影响行数
  108. */
  109. template<typename Fmt,typename ...Args>
  110. int64_t query(int64_t &rowId,vector<vector<string> > &ret, Fmt &&fmt, Args && ...arg){
  111. return queryList(rowId,ret,std::forward<Fmt>(fmt),std::forward<Args>(arg)...);
  112. }
  113. template<typename Fmt,typename ...Args>
  114. int64_t query(int64_t &rowId,vector<list<string> > &ret, Fmt &&fmt, Args && ...arg){
  115. return queryList(rowId,ret,std::forward<Fmt>(fmt),std::forward<Args>(arg)...);
  116. }
  117. template<typename Fmt,typename ...Args>
  118. int64_t query(int64_t &rowId,vector<deque<string> > &ret, Fmt &&fmt, Args && ...arg){
  119. return queryList(rowId,ret,std::forward<Fmt>(fmt),std::forward<Args>(arg)...);
  120. }
  121. /**
  122. * 以printf样式执行sql,并且返回Map类型的结果(包含数据列名)
  123. * @param rowId insert时的插入rowid
  124. * @param ret 返回数据列表
  125. * @param fmt printf类型fmt
  126. * @param arg 可变参数列表
  127. * @return 影响行数
  128. */
  129. template<typename Map,typename Fmt,typename ...Args>
  130. int64_t query(int64_t &rowId,vector<Map> &ret, Fmt &&fmt, Args && ...arg) {
  131. check();
  132. auto tmp = queryString(std::forward<Fmt>(fmt), std::forward<Args>(arg)...);
  133. if (doQuery(tmp)) {
  134. throw SqlException(tmp,mysql_error(&_sql));
  135. }
  136. ret.clear();
  137. MYSQL_RES *res = mysql_store_result(&_sql);
  138. if (!res) {
  139. rowId=mysql_insert_id(&_sql);
  140. return mysql_affected_rows(&_sql);
  141. }
  142. MYSQL_ROW row;
  143. unsigned int column = mysql_num_fields(res);
  144. MYSQL_FIELD *fields = mysql_fetch_fields(res);
  145. while ((row = mysql_fetch_row(res)) != NULL) {
  146. ret.emplace_back();
  147. auto &back = ret.back();
  148. for (unsigned int i = 0; i < column; i++) {
  149. back[string(fields[i].name,fields[i].name_length)] = (row[i] ? row[i] : "");
  150. }
  151. }
  152. mysql_free_result(res);
  153. rowId=mysql_insert_id(&_sql);
  154. return mysql_affected_rows(&_sql);
  155. }
  156. string escape(const string &str) {
  157. char *out = new char[str.length() * 2 + 1];
  158. mysql_real_escape_string(&_sql, out, str.c_str(), str.size());
  159. string ret(out);
  160. delete [] out;
  161. return ret;
  162. }
  163. template<typename ...Args>
  164. static string queryString(const char *fmt, Args && ...arg) {
  165. char *ptr_out = NULL;
  166. asprintf(&ptr_out, fmt, arg...);
  167. if (ptr_out) {
  168. string ret(ptr_out);
  169. free(ptr_out);
  170. return ret;
  171. }
  172. return "";
  173. }
  174. template<typename ...Args>
  175. static string queryString(const string &fmt, Args && ...args) {
  176. return queryString(fmt.data(),std::forward<Args>(args)...);
  177. }
  178. static const char *queryString(const char *fmt) {
  179. return fmt;
  180. }
  181. static const string &queryString(const string &fmt) {
  182. return fmt;
  183. }
  184. private:
  185. template<typename List,typename Fmt,typename ...Args>
  186. int64_t queryList(int64_t &rowId,vector<List> &ret, Fmt &&fmt, Args && ...arg) {
  187. check();
  188. auto tmp = queryString(std::forward<Fmt>(fmt), std::forward<Args>(arg)...);
  189. if (doQuery(tmp)) {
  190. throw SqlException(tmp,mysql_error(&_sql));
  191. }
  192. ret.clear();
  193. MYSQL_RES *res = mysql_store_result(&_sql);
  194. if (!res) {
  195. rowId=mysql_insert_id(&_sql);
  196. return mysql_affected_rows(&_sql);
  197. }
  198. MYSQL_ROW row;
  199. unsigned int column = mysql_num_fields(res);
  200. while ((row = mysql_fetch_row(res)) != NULL) {
  201. ret.emplace_back();
  202. auto &back = ret.back();
  203. for (unsigned int i = 0; i < column; i++) {
  204. back.emplace_back(row[i] ? row[i] : "");
  205. }
  206. }
  207. mysql_free_result(res);
  208. rowId=mysql_insert_id(&_sql);
  209. return mysql_affected_rows(&_sql);
  210. }
  211. inline void check() {
  212. if (mysql_ping(&_sql) != 0) {
  213. throw SqlException("mysql_ping","MYSQL连接异常!");
  214. }
  215. }
  216. int doQuery(const string &sql){
  217. return mysql_query(&_sql,sql.data());
  218. }
  219. int doQuery(const char *sql){
  220. return mysql_query(&_sql,sql);
  221. }
  222. private:
  223. MYSQL _sql;
  224. };
  225. } /* namespace toolkit */
  226. #endif /* SQL_SQLCONNECTION_H_ */