学习实践:使用模式,原则实现一个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 HiDBTable
typedef 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 HiDBTable
typedef 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) ;
#endif
static 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设计模式与开发实践> 在现实中,很多时候也有多种途径到达同一个目的地.比如我们要去某个地方旅游,可以根据具体的实际情况来选择出行的线路. 如果没有时间但 ...
随机推荐
- 小白科普之JavaScript的DOM模型
微信公众号“前端大全”推送了一篇名为“通俗易懂的来讲讲DOM”的文章,把javascript原生DOM相关内容讲解的很详细.仔细读了一遍,觉得整理总结的不错,对自己也很使用,所以把内容整理过来,并根据 ...
- django执行sql
http://docs.30c.org/djangobook2/chapter10/ def first_names(self, last_name): cursor = connection.cur ...
- js异步实现checkbox选中
参考:https://blog.csdn.net/long19901216/article/details/51374064 https://blog.csdn.net/hahei2020/artic ...
- KVM基本概念
在kvm技术中,应用到的两个东西:qemu和kvm.其中kvm负责cpu虚拟化和内存虚拟化,但是kvm不能模拟其他设备,qemu是模拟IO设备(网卡,磁盘),kvm加上qemu之后就能实现真正意义上的 ...
- Codeforces #107 DIV2 ABCD
A #include <map> #include <set> #include <list> #include <cmath> #include &l ...
- pressmuSpiderr
#!/usr/bin/env python # encoding: utf-8 import requests from random import choice from lxml import h ...
- 【bzoj4636】蒟蒻的数列
由于数据范围过大,直接线段树会炸,离散化或者动态开点都行. 打个标记在树上,最后把树dfs一边算一下即可. #include<bits/stdc++.h> #define N 100000 ...
- Hadoop运维记录系列
http://slaytanic.blog.51cto.com/2057708/1038676 Hadoop运维记录系列(一) Hadoop运维记录系列(二) Hadoop运维记录系列(三) Hado ...
- 配置WCF
出处:http://blog.csdn.net/fangxing80/article/details/6106228 前面一篇文章<WCF 学习总结1 -- 简单实例>一股脑儿展示了几种W ...
- python的property的用法
假设定义了一个类:C,该类必须继承自object类,有一私有变量_xclass C: def __init__(self): self.__x=None 1.现在介绍第一种使用属性的方法: 在该类中定 ...