发明内容
为了解决现有技术中的上述问题,本发明提出了一种主内存数据中心(MMDC)的数据处理方法及组件。
具体技术方案是:一种主内存数据中心(MMDC)的数据处理方法:采用统一数据库访问接口即UDBI组件是对主流数据库接口统一抽象封装:当***第一次执行SQL的时候,UDBI会缓存SQL文本及其版本号,如果需要修改,增加SQL,通过PATCH机制更新对应的SQL版本;SQL执行返回的数据集由数据中心单元DATASET组件接受数据;由一个或多个DataSet(数据容器)和保存dataset的结构信息MMDC head组成的MMDC;DATASET的模式有单个进程中使用LOCAL模式:或可以进程间共享的SHARE模式:根据容器数据地址hash值,B*树和B+树索引:建立索引和删除索引:
bool dropIndex(const char*name);
DATA CENTER备份,恢复:
由于MMDC HEAD保存了数据中心的数据字典,并且该字典信息是共享的,而且是可以序列化的,通过该信息就可以执行备份和恢复;具体方法是UNIX下通过SH脚本发送消息,MMDC通过执行Dump(),Recover()来执行,程序意外退出后,恢复在下次启动时进行。
DataSet可以通过如下方式建立:通过定义域的存放数据、删除数据、***数据的命令建立;每次***数据的时候,根据目前DATASET的容量判断是否已经超过已经分配的内存,如果已经超过,就再分配一块连续的内存,块的大小在构建DATASET的时候指定(默认为4k),根据数据量的多少合理指定分配块的大小可以提高内存分配效率。
根据容器数据地址hash值,B*树和B+树索引:建立索引和删除索引:
DATA CENTER备份,恢复:具体方法是UNIX下通过SH脚本发送消息,MMDC通过执行Dump(),Recover()来执行,程序意外退出后,恢复在下次启动时进行。
UDBI FRAMEWORK主要组件:
UDBI:统一数据库访问接口;GenericDAO:数据库执行对象;
DataSet:数据中心单元(MMDC最小数据单元);
SQL Config:执行SQL xml文件配置;SQL xml:SQL配置文件。
其中采用UDBI组件是对主流数据库接口统一抽象封装。当***第一次执行SQL的时候,UDBI会缓存SQL文本及其版本号,如果需要修改,增加SQL,可以通过PATCH机制更新对应的SQL版本,以达到热部署的目的。SQL执行返回的数据集由DATASET组件接受数据。
MMDC由一个或多个DataSet(数据容器)和MMDC head组成(保存dataset的结构信息,可以理解为***数据字典);DATASET的模式有LOCAL模式:只能单个进程中使用,不能共享。SHARE模式:可以进程间共享。主要组件如下:
Dataset:数据容器;DATA:抽象数据(不存放实际数据,只保存数据地址);
MemoyObj:内存结构信息;Allocator:内存分配器;
Row:数据容器中的记录(不存放实际数据,只保存数据地址);
Field:容器字段(类似于数据库表中的COLUMN);
Index:索引类模版(通过它可以对数据容器建立索引);
与现有技术相比,本发明延续了C/C++语言在执行MMDC组件效率上的优势,改进了原有的弊端。
具体实施方式
主要应用于电信级后台计费帐务大数据量处理。
DataSet可以通过如下方式建立:
DataSet ds;
ds.addfield(Field(“f1”,FTSTRING,10));
ds.addfield(Field(“f2”,FTINT));
ds.addfield(Field(“f3”,FTDOUBLE));
ds.addfield(Field(“f4”,FTSTRING,20));
DataSet::iterator it=ds.pushBack();//存放数据:
(*it)[0]=“abc”;
(*it)[1]=12;
(*it)[2]=12.56;
(*it)[3]=“hello”;
ds.erase();//删除数据:
ds.insert()//***数据:
每次***数据的时候,会根据目前DATASET的容量判断是否已经超过已经分配的内存,如果已经超过,就再分配一块连续的内存,块的大小可以在构建DATASET的时候指定(默认为4k),根据数据量的多少合理指定分配块的大小可以提高内存分配效率。
DATASET建立索引:
ds.buildIndex(“indexname”,”filedName”,SORT_TYPE type);
ds.buildIndex(“indexname1”,2,”field1”,field2”);//建复合索引
一个DATASET可以建立多个索引,在执行查找的时候使用。
bool locate(pair<IndexIterator,IndexIterator> & prLoc,size_tindexNo,...);
bool locate(pair<IndexIterator,IndexIterator> & prLoc,size_tindexNo,const Row &row);
删除索引:
bool dropIndex(const char *name);
void dropAllIndex();
索引原理:主要是根据容器数据地址hash值,B*树和B+树索引。
用C/C++抽象UDBI的方法:
统一的访问接口AbstractConnection组件主要的方法有:
virtual void connect(const string & connStr);//连接到数据库
virtual void reconnect();//重新连接到数据库
virtual void disconnect();//断开数据库连接
virtual void beginTrans();//开始事务
virtual void commit();//递交事务
virtual void rollback();//回滚事务
AbstractStatement组件主要方法有:
AbstractStatement(AbstractConnection * conn);
void setSQL(const string & sqlText);//设置执行SQL
void prepareSQL(const string &sqlRef);//准备sql执行
int fetchResultSet(DataSet &ds,int getRows=-1);//取得数据结构集
对于不同的数据库产品实现以上定义统一的数据库访问接口。
比例ORACLE数据库,实现接口后,OracleConnection OracleStatement
使用方法:
AbstractConnection * conn=new OracleConnection();
conn->connect(“user/pwd@sid”);
AbstractStatement * statement=new OracleStatment(conn);
statement->setSQL(“SELECT * FROM TAB1”);
DataSet ds;
statement->fetchResultSet(ds);//取得数据
delete statement;
statement=NULL;
conn->disconnect();
用C/C++解决统一结果返回问题的具体方法:
执行SQL以后,数据库返回结果集,根据数据库中对应的字段的数据类型映射到DataSet的数据类型,以ORACLE为例:
1)DataSet ds;//定义结果集,构建结果集字段
column_desc* desc=this->describe_select(desc_len);
for(int i=0;i<desc_len;++i) {
if(desc[i].dbtype=2)//number {
if(desc[i].scale>0) {
ds.addField(Field(name.c_str(),FTDOUBLE,8)); }
else {
if(desc[i].prec>9) {
ds.addField(Field(name.c_str(),FTSTRING,desc[i].prec)); }
else
ds.addField(Field(name.c_str(),FTINT,4)); } }
else if(desc[i].dbtype=1)//varchar2 {
ds.addField(Field(name.c_str(),FTSTRING,desc[i].dbsize)); }
else if(desc[i].dbtype=12)//date {
ds.addField(Field(name.c_str(),FTSTRING,23)); }
else if(desc[i].dbtype=96)//char {
ds.addField(Field(name.c_str(),FTSTRING,desc[i].dbsize)); }
Else....
2)获取数据到DataSet(ds)
while(!this->eof()) {
DataSet::iterator it=ds.pushBack();
for(size_t i=0;i<ds.fieldCount();++i) {
(*this)>>v;
if((*it)[i].getDataType()==FTSTRING) {
(*it)[i]=v; }
else if((*it)[i].getDataType()==FTINT) {
(*it)[i]=(int)atol(v.c_str()); }
Else if((*it)[i].getDataType()==FTDOUBLE) {
(*it)[i]=atof(v.c_str()); }
Else…. } }
用C/C++实现热部署的具体方法:
每一个SQL都有对应的版本号,一般以时间戳为版本号。
例如sql.mmdd.xxxx
Sql --执行的SQL文本名称
Mmdd.xxxx --SQL版本号(mmdd年月,xxxx毫秒)
另外有一个更新列表,记录目前***运行中每个SQL的版本号,程序执行的时候根据更新列表取得SQL执行版本.
DATA CENTER备份和恢复方法:主要利用UNIX下IPC(进程间通讯)技术结合写文件的方式。进程收到特定的消息后执行dump()方法备份或设置参数定时备份,DataCenter出现运行异常后,下次启动时从最新的备份文件中恢复(如果配置参数是手动恢复,启动时就不执行恢复)。
在具体实施方式中,结合实例说明本组件的工作过程:就拿销帐后台处理为例,主要步骤有:
1)从数据库读取用户基本资料,销帐参数等到DATA CENTER(实际数据保存到DataSet中);参见统一结果返回的方法和SQL热部署的方法。
2)从文件中读取用户欠费帐单到DATA CENTER(实际数据保存到DataSet中)
DataCenter dc;dc.open();
DataSet*ds=new DataSet();
Ds->addfield(Field(“f1”,FTSTRING,10));
Ds->addfield(Field(“f2”,FTINT));
Ds->addfield(Field(“f3”,FTDOUBLE));
Ds->addfield(Field(“f4”,FTSTRING,20));
...
ds->loadFromFile(“../data/f001.dat”);
建立访问索引
ds->buildIndex(“indexname”,”filedName”,SORT_TYPE type);
dc.commit(“dsname”,ds);
...
3)循环每个用户取欠费帐单,调用销帐算法,最后更新DataSet中的数据.
DataSet &ds=dc.getDataSet(“name”);
pair<IndexIterator,IndexIterator>par;
bool locate(par,0,”f1”,“value”);//根据索引查询
calc();//调用业务算法
//更新数据
for(DataSet::IndexIterator iit=par.first;iit!=par.second;++iit)
{ (*iit)[0]=“abc”;
(*iit)[1]=1234;
(*iit)[2]=12.34。