南京邮电大学通达学院 许锦花 07003704
event_inst_id file_id acct_item_type_id old_charge charge tariff_id tariff rate_duration cust_category 话单标识 话单来源 帐目类型 优惠前费用 费用 费率标识 费率 计费时长 DECIMAL(15,0) DECIMAL(12,0) DECIMAL(9,0) NUMERIC(16,5) NUMERIC(16,5) DECIMAL(9,0) NUMERIC(16,5) DECIMAL(9,0) Y Y Y Y Y FK 客户分组标识 DECIMAL(12,0) 表 5,预付费PCS话单费用子表 字段含义 帐目标识 主产品实例标识 帐户标识 客户标识 客户分组 帐目类型标识 帐目来源标识 计费周期标识 费用周期标识 处理来源 优惠费用 优惠前费用 优惠后费用 优惠计算标识 通话时长 计费时长 单位个数 状态 状态时间 数据生成日期 营业区 数据类型 DECIMAL(12,0) DECIMAL(12,0) DECIMAL(12,0) DECIMAL(12,0) DECIMAL(9,0) DECIMAL(9,0) DECIMAL(9,0) DECIMAL(9,0) DECIMAL(9,0) INTEGER NUMERIC(16,5) NUMERIC(16,5) NUMERIC(16,5) DECIMAL(9,0) DECIMAL(9,0) DECIMAL(15,0) DECIMAL(9,0) VARCHAR(3) DATETIME YEAR TO SECOND DATETIME YEAR TO SECOND DECIMAL(9,0) 表 6,预付费PCS话单帐目表 ACCT_ITEM_SD_PREPAYPCS(预付费PCS话单帐目表) 字段名称 acct_item_id serv_id acct_id cust_id cust_category acct_item_type_id item_source_id billing_cycle_id fee_cycle_id deal_source disct_charge old_charge charge disct_express_id duration rate_duration unit_num state state_date created_date area_id 话单格式:
第一行是文件头:
FILEHEAD|100000|100001|100002|100003|100004|200001|300001|300002|100008|100005|100006|100007|160001|160002|160003|160011|160012|160015|160013|160014,FILEHEAD是文件头标识,后面紧接着的一串一串数字是属性标识。接着每一行都是一条话单记录,如
90002|80014|15|023-600003130123456789012345678|02360000312|500060000301|200060000315|1|12912525|20060822000000|20060822000100|10|160001|160002|160003|160011|160012|160015|160013|160014。
- 14 -
非空 说明 Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y PK 南京邮电大学通达学院 许锦花 07003704
入库前的话单经过了预处理标准化。预处理后话单格式为:前半部分为预处理标准事件输出,后半部分是各地预付费特殊属性。 字段名 话单标识 事件类型 网元ID 主叫 被叫 主产品实例标识 客户标识 客户分组 原始文件标识 Cust_id Cust_category Old_file_id Long long Long long Long long Char Char Char 12 9 9 300001 300002 100008 文件ID标识,可以通过关联查找到预处理的文件名 开始时间 结束时间 时长 优惠前费用1 优惠后费用1 优惠前费用2 优惠后费用2 优惠前费用3 优惠后费用3 优惠前费用4 优惠后费用4 优惠前费用5 优惠后费用5 优惠前费用6 优惠后费用6 是否需要计算跳次 计费方标志 Start_time End_time duration Pcs_oldcharge1 Pcs_charge1 Pcs_oldcharge2 Pcs_charge2 Pcs_oldcharge3 Pcs_charge3 Pcs_oldcharge4 Pcs_charge4 Pcs_oldcharge5 Pcs_charge5 Pcs_oldcharge6 Pcs_charge6 PCS_ORSHIHUA DATETIME DATETIME long double double double double double double double double double double double double Int Char Char 14 14 100005 100006 100007 160001 160002 160003 160011 160012 160013 160014 160015 160016 160017 160018 160019 160020 160021 格式:yyyymmddhhmmss 格式:yyyy-mm-dd hh:mm:ss 字段代码 event_inst_id Event_type_id net_ID Calling_nbr CALLED_NBR Serv_id 数据类型 Long long Long long Long long char Char Long long 接口类型 char Char Char Char char Char 长度 12 9 9 20 20 12 属性标识 描述 100000 100001 100002 100003 100004 200001 网元标识 主叫,带区号 被叫 long 14 double 10 double 10 double 10 double 10 double 10 double 10 double 10 double 10 double 10 double 10 double 10 double 10 Int char 1 5 PCS_BILLINGFLAG char 表 7,话单格式
预付费入库设计
预付费入库就是将拣重以后的话单文件,经过处理,解析并提取其中的信息,然后把这些信息入库,将它们以表的结构存放在数据库中,总的来说它实现的是从文件级到表级的过程。入库后产生了三张表:清单表、费用表和总帐(sd)表。清单表、费用表是给web前台查询用的,为客户提供清单级的查询;
- 15 -
南京邮电大学通达学院 许锦花 07003704
sd表的帐目数据是给后面出帐用的,可以为客户提供总帐级的查询。由于电信计费时的数据量很大,入库时,对数据库的操作会很慢,而电信计费要求是快速的实现计费,为了提高程序的速度要采取措施:批量入库,即写数据库时我们采用批量操作,当提取的记录达到一定数目时,把它们一起写入数据库,从而可以实现快速的对数据库进行写操作。 实现从文件级到表级的转换,关键是如何提取文件中的话单记录并把它放到表中相应得位置中,在这里我们用的是事件驱动来实现,即先读取话单文件的头文件,把它属性标识ID存放到当前文件的属性ID序列中;然后取出一条话单记录,依次读取话单字段,然后根据当前文件的属性ID序列中对应属性标识ID来设置话单属性,并把它存放到话单计费事件适配器类(TCdrEvent)中的计费原数据结构(TCallDetailRecord)pRecordData的对应的成员变量里。要提取相应得字段的信息时,再用属性标识ID来匹配取得。
填写清单表、费用表和sd表时会有所不同,清单表的字段可以直接从中间数据pRecordData中获得,费用表的字段通过清单表,查找帐目类型表来填写。填写sd表时还必须查找服务资料和查找帐务关系来填写相关字段。
入清单表和费用表与入sd表也有不同,入清单表和费用表时,只要将解析出的记录写进对应的表中即可,而入sd表时比较复杂,新记录还要与对应sd表中的记录比较,如果没有记录才写入新的纪录,有相同记录要修改记录。对数据库的读写操作会很慢,为了提高程序的速度,把需要进行查找的sd表的信息以Hash表的形式先存入内存,另外再申明两个Hash容器:insert容器和update容器。用新记录与Hash内存的记录比较,如果没有记录,对insert容器进行操作,用新记录与insert容器中的记录比较,insert容器中有记录就修改该记录,insert容器没有记录就把新记录放入其中;如果Hash内存有记录,就对update容器进行操作,用新记录与update容器中的记录比较,update容器中有记录就修改该记录,update容器没有记录就把新记录放入其中。在入库时,把 insert容器中的数据写进sd表里,用update容器中的数据修改sd表对应得记录;然后还要用insert容器和update容器的数据更新Hash内存使其与数据库中的sd表同步。
Hash内存等这些在计费系统的其他模块中也用到过,相关结构和申明都已经写好放在公用的库中,在这里我们只要使用它,所以不会细讲它。但它是计费系统的重要部分,通过它,才使程序能够快速的运行。
预付费入库与计费系统的合帐模块有些类似,在设计预付费入库时会参考合帐模块的相关设计思想。 3.1 预付费入库基类的设计
3.1.1 预付费入库基类(TPcsTrans)的设计
TPcsTrans的主要功能是处理话单文件,把话单文件解析成一条一条的话单记录,并把它们写入数据库。因为对数据库的操作很慢,会占用大量的运行时间,所以先把这些记录放在内存中,等到达一定数量时,再成批的放入数据库,为此我们需要一个用于存放这些记录的空间,所以我们还要设计一个数据组织操作类(数据库缓冲区)TEventPcsInfo,并把它作为TPcsTrans的一个成员。
为了安全,要设计一个处理函数接口:处理函数Execute(),在它里面可以调用私有成员函数。另外还需要一些私有成员函数:根据执行方式预设查询SQL PreSetQuerySQL(), 读取配置信息
GetConfigInfo(),处理文件函数ProcessPcsFile(),处理单条记录DealOneCdr(),完成一个文件操作同时入库:DoneOneFile()。还要一个成员变量TTbInfoManager(内存资料类)的成员。还需要成员变量:存放已经处理的文件信息 vector
public: // 构造函数
- 16 -
南京邮电大学通达学院 许锦花 07003704
TPcsTrans(TAppComponent *pParent,TTbInfoManager *pTbInfoManagerPara,TPCSInfoManager *pPcsInfoManagerPara) :
TAppComponent(pParent),m_EventPcsInfo(NULL),m_pclTbInfoManager(pTbInfoManagerPara),m_iCount(100000) {
m_EventPcsInfo = new (nothrow)TEventPcsInfo(pParent,pPcsInfoManagerPara); if(!m_EventPcsInfo) {
throw TException(\ }
m_vFileProc.clear();
};
// 析构函数
virtual ~TPcsTrans() {
delete m_EventPcsInfo;
m_EventPcsInfo = NULL; }; // 处理
bool Execute(TPcsTransExecInfo &tPcsTransExecInfo);
// 根据执行方式预设查询SQL
bool PreSetQuerySQL(const TPcsTransExecInfo &tPcsTransExecInfo, char *psSQL); // 读取配置信息
bool GetConfigInfo(TConfigInfo &tConfigInfo); // 处理话单文件
bool ProcessPcsFile(const char *psSQL,
TPcsTransExecInfo &tPcsTransExecInfo,
TConfigInfo &tConfigInfo); //处理单条记录
private:
bool DealOneCdr(TRateFileIOManager &clRateFileIOMan,TCdrEvent &tCdrEvent,TPcsTransExecInfo &tPcsTransExecInfo);
//完成一个文件操作同时入库
bool DoneOneFile(TRateFileIOManager &clRateFileIOMan, TRateFileDBInterface &clRateFileDBIF, TEventSourceFileInfo *ptUnsettledFileInfo,
TPcsTransExecInfo &tPcsTransExecInfo);
private:
//内存数据管理类
TEventPcsInfo *m_EventPcsInfo; //预设的入库缓冲区记录数量
int m_iCount;
//复用批价组件需要传入的构造指针,只需要初始化
TTbInfoManager *m_pclTbInfoManager; //存放已经处理的文件信息
- 17 -
南京邮电大学通达学院 许锦花 07003704
vector
3.1.2数据组织操作类(TeventPcsInfo)的设计
由上面类TPcsTrans对它的要求,TeventPcsInfo必须具备内存空间用于存储数据,且还要有把内存中的数据写入数据库的功能。先来设计用于存储数据,预付费入库最后要形成三张表:清单表、费用表和SD表。清单表、费用表只需要进行入库,定义为vector向量即可实现;SD表的入库时候,要和原来的记录进行比较,有了记录要进行合帐,没有记录插入记录,如果不采取任何措施的话程序会很慢,因此我们要用到Hash表(HASHTABLE),用它来定义内存空间,先把SD表读到内存,产生一条记录时,先查找SD表,如果有了记录把它放到更新的Hash内存中,没有记录把它放到插入的Hash内存中。入库的时候会产生当前帐期和下个帐期的概念,所以以上成员变量都要设计出两份。另外还有一些成员变量来辅助实现上述功能。
把数据写入数据库要靠成员函数来实现,因此要设计了一些成员函数:批量文件入库PcsIntoDB(),话单记录到入库结构的转换Convert(),往数据集合类里面插入数据InsertPcsElement()
InsertPcsFeeElement(),将一个文件处理成功的结果插入容器InsertOneFileResult(),处理失败时清除记录结果ClearOneFileResult()等。为了方便类TPcsTrans对它操作,将类TPcsTrans定义为TEventPcsInfo的友元类。
class TEventPcsInfo:public TComponent {
friend class TPcsTrans; public:
inline int GetBufferCount() {
return iBufferCount; } // 批量文件入库
bool PcsIntoDB(TPcsTransExecInfo &tPcsTransExecInfo);
//完成预处理输入到入库结构的转换,中间复用了批价的事件组件
bool Convert(TCdrEvent &tCdrEvent, TPcsTransExecInfo &tPcsTransExecInfo); //获得对应事件类型的帐目类型
int GetAcctItemType(char* service_type);
//根据业务类型和话单类型判断费用项是否插入nor_result:基本费用 other_result:其它费用 void IfInsert(const char *pBusType,const char *pTicketType,int &nor_result,int &
other_result);
//往数据集合类里面插入数据
bool InsertPcsElement() bool InsertPcsFeeElement()
//将一个文件处理成功的结果插入容器 bool InsertOneFileResult(); //处理失败时清除记录结果 bool ClearOneFileResult(); private:
vector
- 18 -