下面我们可以开始设计数据库模块了
一个正常的服务器,多半是需要数据库功能的。 当时在C++环境下,好的数据库代码并不多
什么是好的数据库代码?
- 满足数据库的接入要求
- 使用方便简洁
- 自动化程度高
- 适配性广泛
这里我们将一起研究一下,如何实现一个好的数据库模块,方便我们的使用
需求说明
现在我们要搞清楚,数据库到底有哪些接入要求。 首先,我们需要有一个能灵活修改的数据结构,方便我们去适配数据库中各种表的内容 这意味着我们需要一个动态可调表类。
其次,我们需要表的创建、查询SQL语句自动化生成功能。 这样我们可以方便的处理表
最后,我们还需要一套数据库接口,提供数据库的连接、查询和结果的获取
当然,一些配套的功能也是不能少的。 比如数据库关闭,查询失败的处理等等。
这些需求中,最麻烦的是动态创建一个和表呼应的类,来方便进行数据库创建、存储和查询 这里面需要用到一些宏的技巧,和类的设计的技巧。 此外,还需要大量的辅助类,来记录列信息,表信息,结果信息等等。
而且数据库类应该是一个接口类,配合一些具体实现的类。 这样可以方便对接不同的数据库
依赖实现
class ValueTool {
//判断是否存在toString
template<typename U, String(U::*)()>struct HELP;
template<typename U>static char Test(HELP<U, &U::toString>*);
template<typename U>static int Test(...);
//判断是否存在c_str
template<typename U, const char* (U::*)() const>struct HELP1;
template<typename U>static char Test1(HELP<U, &U::toString>*);
template<typename U>static int Test1(...);
public:
const static bool has_toString = sizeof(Test<value>(0)) == sizeof(char);
const static bool has_c_str = sizeof(Test1<Value>(0) == sizeof(char));
static std::enable_if<has_toString,String>
toString(const Value& v) {
return v.toString();
}
static std::enable_if<has_c_str,String>
toString(const Value& v) {
return _T("\"") + v + _T("\"");
}
String toString(const char* v) {
return _T("\"") + String(v) + _T("\"");
}
static std::enable_if<!has_toString && !has_c_str,String>
toStriing(const Value& v) {
StrStream s;
s << v;
return s.str();
}
};
using CParamIter = StrList::const_iterator;
using ParamIter = StrList::iterator;
struct StrListParam{
template<typename ..._ARGS_>
StrListParam(const _ARGS_&...args) {
int _[] = { (Append(args),0)... };
}
StrListParam(const StrListParam& slp) {
lstParams.insert(lstParams.end(), slp.lstParams.begin(), slp.lstParams.end());
}
StrListParam& operator=(const StrListParam& slp) {
if (this != &slp) {
lstParams.insert(lstParams.end(), slp.lstParams.begin(), slp.lstParams.end());
}
return *this;
}
CParamIter begin()const { return lstParams.begin(); }
ParamIter begin() { return lstParams.begin(); }
CParamIter end()const { return lstParams.end(); }
ParamIter end() { return lstParams.end(); }
size_t size() const { return lstParams.size(); }
StrList lstParams;
private:
template<typename TAIL>
void Append(const TAIL& tail) { lstParams.push_back(tail); }
};
using SLParam = struct StrListParam;
#define _V(X) ValueTool::toString((X))
struct _Field_{
public:
virtual String Create();
_Field_() { Attr = NONE; }
_Field_(const _Field_& field);
virtual ~_Field_() { Attr = NONE; }
virtual _Field_& operator=(const _Field_& field);
virtual void FromString(const String& sValue);
virtual String toEqualExp()const = 0;
String FullName()const;
virtual String toString()const = 0;
public:
String Name;
String Type;
unsigned Attr;
String Default;
String Check;
};
template<typename T>
class _DeclareField :public _Field_
{
public:
_DeclareField() :_Field_() { value = T(); }
_DeclareField(const _DeclareField& field) :_Field_(field) {
value = field.value;
}
virtual ~_DeclareField() {}
virtual _Field_& operator=(const _Field_& field) {
if (this != &field) {
_Field_::operator=(field);
value = dynamic_cast<const _DeclareField<T>&>(field).value;
}
return *this;
}
virtual void FromString(const String& sValue) { _Field_::FromString(sValue); }
T& Value() { return value; }
public:
T value;
};
template<>
class _DeclareField<void> :public _Field_
{
public:
_DeclareField() :_Field_() { value = nullptr; }
_DeclareField(const _DeclareField& field) :_Field_(field) {
value = nullptr;
}
virtual ~_DeclareField(){}
virtual _DeclareField& operator=(const _DeclareField& field) {
return *this;
}
virtual void FromString(const String& sValue) {}
void* Value() { return value; }
public:
void* value;
};
using FieldArray = std::vector<std::shared_ptr<_Field_>>;
using FieldMap = std::map<String, std::shared_ptr<_Field_>>;
using FMapIter = FieldMap::iterator;
using FMapCIter = FieldMap::const_iterator;
using PField = std::shared_ptr<_Field_>;
struct _Table_ {
public:
_Table_() {}
_Table_(const _Table_& table) {
Database = table.Database;
Name = table.Name;
Columns = table.Columns;
Fields = table.Fields;
}
virtual String Create();
virtual String Insert(const SLParam& Columns, const SLParam& Values);
virtual String Drop();
virtual String Modify(const SLParam& Columns, const SLParam& Values);
virtual String Query();
virtual std::shared_ptr<_Table_>Copy()const = 0;
String FullName()const;
public:
String Database;//表所属的库
String Name;
FieldArray Columns;
FieldMap Fields;
};
using PTable = std::shared_ptr<_Table_>;
using TableArray = std::vector<PTable>;
using TableList = std::list<PTable>;
#define DECLARE_TABLE_CLAEE(name) \
class name:public _Table_{ \
public: \
virtual PTable Copy()const{return PTable(new name(*this));} \
name():_Table_(){Name=_T(#name);
#define DECLARE_ITEM(name,attr,type,size,Default,check) \
{PField field(new type(_T(#name),attr,_T(size),_T(Default),_T(check))); \
Columns.push_back(field); \
Fields.insert(std::pair<String,PField>(_T(#name),field));}
#define DECLARE_TABLE_CLASS_END() }};
这里有两个类比较重要 _Field_ 、 _Table_
考虑到数据中,最重要的核心就是表,所以我们设计了表的基类_Table_
而表又是由若干列组成,所以我们设计了基类_field_