学习实践:使用模式,原则实现一个C++数据库訪问类
一、概述
二、接口
(一)接口概述
我设计的异常例如以下:
/** @brief 数据库操作异常 */class HI_DB_EXPORT HiDBException{public:HiDBException();public:std::string ToSrting();public:std::string m_sql; /**< 本次操作的SQL语句 */std::string m_descript; /**< 异常描写叙述 */std::string m_position; /**< 异常位置 */long m_errorId; /**< 异常编号 */HiDBType m_dbTyp; /**< 数据库类型 */};
/** @brief 异常语句宏 */#define HiDBHelperOnError(ps, script,sql, id) \HiDBException exception;\exception.m_position = ps;\exception.m_descript = script;\exception.m_sql = sql;\exception.m_errorId = id;\throw exception;\//return false;
(二)详细接口
/** @brief 数据库类型 */enum HiDBType{HiDBType_Invail, /**< 无效类型 */HiDBType_MySQL, /**< MySQL */};
/*** @brief 构造函数* @param[in] type 数据库类型* @param[in] isUsingLock 是否须要使用相互排斥锁*/HiDB(HiDBType type = HiDBType_MySQL, bool isUsingLock = false);
/*** @brief 打开数据库连接* @param[in] conn 数据库连接字符串* @retval true:成功。false;失败* @par 实例:* @code* HiDB db;* if (db.Open("host=127.0.0.1;port=3306;dbname=test;user=root;pwd=root;charset=gbk;"))* {* // 打开成功* }* else* {* // 打开失败* }* @endcode*/bool Open(const char* conn) throw (HiDBException);
不同数据库,须要满足特定的格式,在MySQL中,要使用类似于“host=127.0.0.1;port=3306;dbname=test;user=root;pwd=root;charset=gbk;”的格式。
/*** @brief 关闭据库连接*/void Close(void);
/*** @brief 数据库连接是否打开*/bool IsOpen();
/*** @brief 运行SQL语句。并不返回结果* @param[in] conn SQL语句* @retval true:成功。false;失败* @par 实例:* @code* HiDB db;* if (db.ExecuteNoQuery("UPDATE table SET Paramer1='%s'* and Paramer2='%s' OR Paramer3=%d", "test1", "test2", 3))* {* // 运行成功* }* else* {* // 运行失败* }* @endcode*/bool ExecuteNoQuery(const char* sql, ...) throw (HiDBException);
触发异常时,抛出HiDBException异常。
/*** @brief 运行SQL语句,返回一个结果* @param[in] sql SQL语句* @retval 获得的数据。假设为空,则失败*/std::string ExecuteScalar(const char* sql, ...) throw (HiDBException);
#ifndef HiDBTabletypedef std::map<std::string, std::string> HiDBMap;/** @brief 查询结果 */typedef std::vector<HiDBMap> HiDBTable; /**< 查询结果 */#endif
/*** @brief 运行SQL语句,返回一个结果集合* @param[in] sql SQL语句* @retval 存储查询记录的智能指针*/std::shared_ptr<HiDBTable> ExecuteQuery(const char* sql, ...) throw (HiDBException);
该对象为无參无返回值的函数对象就可以。stl中提供了function对象。
(在最初的版本号中是自己实现函数对象的)
/*** @brief 在事务中运行处理* @param[in] fun 处理函数*/void OnTransaction(const std::function<void()>& fun) throw (HiDBException);
(三) 接口的使用案例
HiDB m_DB = new HiDB(HiDBType_MySQL, true);try{bool ret = m_DB->Open("host=127.0.0.1;port=3306;dbname=test;user=root;pwd=root;charset=gbk;");m_DB->ExecuteNoQuery("drop table if exists table1;");string val = m_DB->ExecuteScalar("SELECT column4 FROM table1 WHERE column1='%s' AND column3=%d",&val, "hitest", 59);shared_ptr<HiDBTable> table = this->m_DB->ExecuteQuery("SELECT * FROM table1 WHERE column1='%s' OR column1='%s'","hitest", "mytest");}catch(HiDBException& e){// ...}
(四) 其它
(五) 完整的接口:
#pragma once/*** @defgroup 数据库模块* @{*/#include "HiDBExport.h"#include <string>#include <vector>#include <map>#include <sstream>/** @brief 数据库类型 */enum HiDBType{HiDBType_Invail, /**< 无效类型 */HiDBType_MySQL, /**< MySQL */};#ifndef HiDBTabletypedef std::map<std::string, std::string> HiDBMap;/** @brief 查询结果 */typedef std::vector<HiDBMap> HiDBTable; /**< 查询结果 */#endif/** @brief 数据库操作异常 */class HI_DB_EXPORT HiDBException{public:HiDBException();public:std::string ToSrting();public:std::string m_sql; /**< 本次操作的SQL语句 */std::string m_descript; /**< 异常描写叙述 */std::string m_position; /**< 异常位置 */long m_errorId; /**< 异常编号 */HiDBType m_dbTyp; /**< 数据库类型 */};/** @brief 异常语句宏 */#define HiDBHelperOnError(ps, script,sql, id) \HiDBException exception;\exception.m_position = ps;\exception.m_descript = script;\exception.m_sql = sql;\exception.m_errorId = id;\throw exception;\//return false;/**//** @}*/ // 数据库模块
#pragma once/*** @defgroup 数据库模块* @{*/#include <memory>#include <functional>#include "HiDBCommon.h"class HiDBImpl;#pragma warning (disable: 4290)/*** @brief 数据库操作类,封装数据库的通用操作,本类使用策略模式实现* @author 徐敏荣* @date 2012-06-14** @par 修订历史* @version v0.5 \n* @author 徐敏荣* @date 2012-06-14* @li 初始版本号* @version v0.6 \n* @author 徐敏荣* @date 2014-08-04* @li 简化程序**/class HI_DB_EXPORT HiDB{public:/*** @brief 构造函数* @param[in] type 数据库类型* @param[in] isUsingLock 是否须要使用相互排斥锁*/HiDB(HiDBType type = HiDBType_MySQL, bool isUsingLock = false);/*** @brief 析构函数*/~HiDB();public:/*** @brief 打开数据库连接* @param[in] conn 数据库连接字符串* @retval true:成功。false。失败* @par 实例:* @code* HiDB db;* if (db.Open("host=127.0.0.1;port=3306;dbname=test;user=root;pwd=root;charset=gbk;"))* {* // 打开成功* }* else* {* // 打开失败* }* @endcode*/bool Open(const char* conn) throw (HiDBException);/*** @brief 关闭据库连接*/void Close(void);/*** @brief 数据库连接是否打开*/bool IsOpen();public:/*** @brief 运行SQL语句,并不返回结果* @param[in] conn SQL语句* @retval true:成功。false;失败* @par 实例:* @code* HiDB db;* if (db.ExecuteNoQuery("UPDATE table SET Paramer1='%s'* and Paramer2='%s' OR Paramer3=%d", "test1", "test2", 3))* {* // 运行成功* }* else* {* // 运行失败* }* @endcode*/bool ExecuteNoQuery(const char* sql, ...) throw (HiDBException);public:/*** @brief 运行SQL语句。返回一个结果* @param[in] sql SQL语句* @retval 获得的数据,假设为空,则失败*/std::string ExecuteScalar(const char* sql, ...) throw (HiDBException);public:/*** @brief 运行SQL语句,返回一个结果集合* @param[in] sql SQL语句* @retval 存储查询记录的智能指针*/std::shared_ptr<HiDBTable> ExecuteQuery(const char* sql, ...) throw (HiDBException);public:/*** @brief 在事务中运行处理* @param[in] fun 处理函数*/void OnTransaction(const std::function<void()>& fun) throw (HiDBException);private:/*** @brief 数据库操作实现指针*/HiDBImpl* m_Impl; /**< 数据库操作实现指针 */};/**//** @}*/ // 数据库模块
三 实现
(一) 可变參数的处理
#if !defined(HISDB_ON_VARLIST)#define HISDB_ON_VARLIST(x, y) \char chArr[2048] = {0};\char* pchar = &chArr[0];\va_list pArgList;\va_start(pArgList, y);\::_vsnprintf(chArr, 2047, x, pArgList); \va_end(pArgList) ;#endif
(二) 相互排斥锁的实现
/*** @brief 临界区訪问类,主要封装windows临界区的訪问,该类主要在栈中使用,利用局部变量的构造和析构函数出入临界区* @author 徐敏荣* @date 2012-06-14** @par 修订历史* @version v0.5 \n* @author 徐敏荣* @date 2012-06-14* @li 初始版本号**/class HiCritical{public:/*** @brief 构造函数*/HiCritical(){::InitializeCriticalSection(&cs);}/*** @brief 析构函数*/~HiCritical(){::DeleteCriticalSection(&cs);}/*** @brief 进入临界区*/void Enter(){::EnterCriticalSection(&cs);}/*** @brief 离开临界区*/void Leave(){::LeaveCriticalSection(&cs);}CRITICAL_SECTION* GetSection(){return &cs;}private:/*** @brief 临界区对象*/CRITICAL_SECTION cs; /**< 临界区对象 */};
/*** @brief 临界区訪问管理类。利用构造函数进入临界区。利用西沟函数离开临界区* 假设向构造函数提供NULL參数,则不使用临界区。**/class HiCriticalMng{public:HiCriticalMng(HiCritical& crl): cl(&crl){cl->Enter();}HiCriticalMng(HiCritical* crl): cl(crl){if (cl){cl->Enter();}}~HiCriticalMng(){if (cl){cl->Leave();}}private:HiCritical* cl;};
(三) HiDBImpl的接口
#pragma once/*** @defgroup 数据库操作实现类接口类* @brief 数据库操作实现类接口类,声明数据库操作实现类的接口。* @author 徐敏荣* @date 2012-06-14** @par 修订历史* @version v0.5 \n* @author 徐敏荣* @date 2012-06-14* @li 初始版本号* @{*/#include "DB/HiDB.h"class HiCritical;/*** @brief 数据库操作实现类接口类。声明数据库操作实现类的接口**/class HiDBImpl{public:/*** @brief 构造函数* @param[in] isUsingLock 是否须要使用相互排斥锁*/HiDBImpl(bool isUsingLock);/*** @brief 析构函数*/virtual ~HiDBImpl();public:/*** @brief 打开数据库连接* @param[in] conn 数据库连接字符串* @retval true:成功,false;失败*/virtual bool Open(const char* conn) = 0;/*** @brief 关闭据库连接*/virtual void Close(void) = 0;public:/*** @brief 运行SQL语句。并不返回结果* @param[in] conn SQL语句* @retval true:成功。false;失败*/virtual bool ExecuteNoQuery(const char* sql) = 0;public:/*** @brief 运行SQL语句。返回一个结果* @param[in] sql SQL语句* @param[out] value 取得的结果* @retval true:成功,false。失败*/virtual std::string ExecuteScalar(const char* sql) = 0;public:/*** @brief 运行SQL语句。返回一个结果集合* @param[in] sql SQL语句* @param[out] table 取得的结果集合* @retval true:成功,false;失败*/virtual std::shared_ptr<HiDBTable> ExecuteQuery(const char* sql) = 0;public:/*** @brief 事物处理* @retval true:成功,false;失败*/virtual void OnTransaction(const std::function<void()>& fun) = 0;protected:/*** @brief 临界区对象。为空表示不须要考虑资源并发訪问*/HiCritical* m_pCritical;};/**//** @}*/ // 数据库操作实现类接口类
(四)HiDB的实现:
#include <stdarg.h>#include "DB/HiDB.h"#include "HiDBMySQL.h"using namespace std;#if !defined(HISDB_ON_VARLIST)#define HISDB_ON_VARLIST(x, y) \char chArr[2048] = {0};\char* pchar = &chArr[0];\va_list pArgList;\va_start(pArgList, y);\::_vsnprintf(chArr, 2047, x, pArgList); \va_end(pArgList) ;#endifstatic bool IsImplOK(HiDBImpl* db){if (!db){return false;}/*if (!db->IsOpen()){return false;}*/return true;}// 构造函数HiDB::HiDB(HiDBType type, bool isUsingLock):m_Impl(NULL){if (type == HiDBType_MySQL){this->m_Impl = new HiDBMySQL(isUsingLock);}}// 析构函数HiDB::~HiDB(){if (this->m_Impl){delete this->m_Impl;this->m_Impl = NULL;}}// 打开数据库连接bool HiDB::Open(const char* conn){if (!this->m_Impl){return false;}return this->m_Impl->Open(conn);}bool HiDB::IsOpen(){if (!this->m_Impl){return false;}return true;//this->m_Impl->IsOpen();}void HiDB::Close(void){if (!IsImplOK(this->m_Impl)){return;}return this->m_Impl->Close();}bool HiDB::ExecuteNoQuery(const char* sql, ...){if (!IsImplOK(this->m_Impl)){return false;}HISDB_ON_VARLIST(sql, sql);return this->m_Impl->ExecuteNoQuery(chArr);}string HiDB::ExecuteScalar(const char* sql, ...){if (!IsImplOK(this->m_Impl)){return "";}HISDB_ON_VARLIST(sql, sql);return this->m_Impl->ExecuteScalar(chArr);}std::shared_ptr<HiDBTable> HiDB::ExecuteQuery(const char* sql, ...){if (!IsImplOK(this->m_Impl)){return NULL;}HISDB_ON_VARLIST(sql, sql);return this->m_Impl->ExecuteQuery(chArr);}void HiDB::OnTransaction(const std::function<void()>& fun){if (!IsImplOK(this->m_Impl)){HiDBHelperOnError("HiDB::OnTransaction","HiDB is not impl", "", 0);}return this->m_Impl->OnTransaction(fun);}
四 后记
类图将在本文后面提供。
学习实践:使用模式,原则实现一个C++数据库訪问类的更多相关文章
- 学习实践:使用模式,原则实现一个C++数据库访问类
一.概述 在我参与的多个项目中,大家使用libMySQL操作MySQL数据库,而且是源码即复用,在多个项目中有多套相同或相似的源码,这样的复用方式给开发带来了不变,而且libMySQL的使用比较麻烦, ...
- Java并发学习之十五——使用读写锁同步数据訪问
本文是学习网络上的文章时的总结.感谢大家无私的分享. 读写锁重要的是写锁的使用,仅仅用一个入口. 以下是读写锁使用的样例 package chapter2; import java.util.conc ...
- Java设计模式(三) Visitor(訪问者)模式及多分派场景应用
基本概念 Visitor 封装一些作用于数据结构中的各元素的操作,不同的操作能够借助新的visitor实现.减少了操作间的耦合性 訪问者能够将数据结构和对数据的操作解耦,使得添加对数据结构的操作不须要 ...
- JAVA设计模式之:訪问者模式
訪问者模式: 一个作用于某对象结构中各元素的操作,使你能够在不改变各元素类数据结构的前提下添加作用于这些元素的新操作. 结构对象是訪问者模式必备条件.且这个结构对象必须存在遍历自身各个对象的方法. 适 ...
- 15一个NoSql数据库
随着因特网web2.0该网站的兴起.非关系型数据库,现在已经成为一个非常受欢迎的新领域.非关系数据库产品的发展非常迅速.而在处理传统的关系数据库web2.0现场.特别是大规模,高并发SNS类型web2 ...
- 设计模式入门之訪问者模式Visitor
//訪问者模式定义:表示一个作用于某对象结构中的各个元素的操作,它使你能够在不改变各元素类的前提下定义作用于这些元素的新操作. //从定义上看.这个模式跟装饰模式的定义非常类似(动态地给一个对象加入一 ...
- 利用JS跨域做一个简单的页面訪问统计系统
事实上在大部分互联网web产品中,我们一般会用百度统计或者谷歌统计分析系统,通过在程序中引入特定的JS脚本,然后便能够在这些统计系统中看到自己站点页面详细的訪问情况.可是有些时候,因为一些特殊情况,我 ...
- 前端学习实践笔记--JavaScript深入【1】
这一年中零零散散看过几本javascript的书,回过头看之前写过的javascript学习笔记,未免有点汗颜,突出“肤浅”二字,然越深入越觉得javascript的博大精深,有种只缘身在此山中的感觉 ...
- JavaScript设计模式与开发实践 - 策略模式
引言 本文摘自<JavaScript设计模式与开发实践> 在现实中,很多时候也有多种途径到达同一个目的地.比如我们要去某个地方旅游,可以根据具体的实际情况来选择出行的线路. 如果没有时间但 ...
随机推荐
- bzoj 3190 维护栈
我们可以将每一辆赛车看成一条直线,斜率为速度,纵截距为初始位置,那么问题就转化为求这n条直线处于最上面的直线.最上面是指在坐标系中,假设从x轴向下看,能看到的直线,只露一个点也算能看见.那么就类似水平 ...
- 硬币问题 tarjan缩点+DP 莫涛
2013-09-15 20:04 题目描述 有这样一个游戏,桌面上摆了N枚硬币,分别标号1-N,每枚硬币有一个分数C[i]与一个后继硬币T[i].作为游戏参与者的你,可以购买一个名为mlj的小机器人, ...
- PHP HERE DOCUMENT
转自: http://www.codeweblog.com/php%E4%B8%ADheredoc%E7%9A%84%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95/ Here ...
- [Leetcode Week5]Word Ladder
Word Ladder题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/word-ladder/description/ Description Give ...
- 《简明python教程》笔记三
图形软件(GUI工具) 可供选择的GUI: 一.PyQT 是Qt工具包的python绑定.Qt工具包是构建KDE的基石.linux下使用免费,windows下使用收费. 二.PyGTK 是GTK+工具 ...
- centos6.5 挂载远程目录
查看nfs程序是否安装: [root@crawler_mv02 ~]# rpm -qa |grep rpcbindrpcbind-0.2.0-13.el6_9.1.x86_64[root@crawle ...
- 针对“永恒之蓝”攻击紧急处置手册(蠕虫 WannaCry)
首先确认主机是否被感染 被感染的机器屏幕会显示如下的告知付赎金的界面: 如果主机已被感染: 则将该主机隔离或断网(拔网线).若客户存在该主机备份,则启动备份恢复程序. 如果主机未被感染: 则存在四种方 ...
- (十一)数组array
变量:只能存一个值,数组可以存多个值 (1)普通数组,索引下标是整数: 1)定义: 方法一:一次赋一个值:语法:数组名[下标]=变量值 array[1]=linux array[2]=shell 方法 ...
- MySQL密码不能登陆问题
由于种种原因,在进行开发的时候我一直是基于Windows平台,并且以前初学的时候常常重装不同版本的 MySQL数据库.因此长时间不使用后就产生了一些冲突的问题. 简单描述下,今天用以前 ...
- Codeforces Round 254 (Div. 2)
layout: post title: Codeforces Round 254 (Div. 2) author: "luowentaoaa" catalog: true tags ...