数据库(2):配置数据的缓存建立方法,建立通用表模型
来源:互联网 发布:淘宝个人第一大卖家 编辑:程序博客网 时间:2024/06/07 10:39
用于建立大量的数据表事务,建模过程无需关心数据数据表内容
例子: 一下是sqlite数据库的静态数据处理方案,改造一下可以成为静态和动态数据的缓存方案
/*! \file csvtable.h
fileencoding:utf-8
\brief 读取csv文件
\author
\date
*/
#ifndef HANJJ_CSVTABLE_H
#define HANJJ_CSVTABLE_H
#include <string>
#include <map>
#include <vector>
#include <tr1/unordered_map>
#include "csv.h"
#define USE_SQLITE3 1
#ifdef USE_SQLITE3
#include <sqlite3.h>
#endif
//! 整型和整型的HashMap
typedef std::tr1::unordered_map< int, int > HashMap;
//! 整型和整型的HashMultiMap
typedef std::tr1::unordered_multimap< int, int > HashMultiMap;
//! @name 处理csv表的回调函数,表索引id唯一
//@{
//! 处理field,一个数据
void cb1(void* s, size_t len, void* data);
//! 处理row,遇到一行结束
void cb2(int c, void* data);
//@}
/* 用不用这里不知道,注释掉先
//! @name 处理csv表的回调函数,表索引id不唯一
//@{
//! 处理field,一个数据
void cb1m(void* s, size_t len, void* data);
//! 处理row,遇到一行结束
void cb2m(int c, void* data);
//@}
*/
//! 处理csv表的类
/*!
表结构如下
\code
+--------+------------+-------+
| keyid | aux_keyid | name1 |
+--------+------------+-------+
| 1 | 5 | ok |
+--------+------------+-------+
对于唯一id索引表,即keyid不重复,可以使用
std::string& getRec(int keyid, std::string& col_name) throw(std::string)
例如 string s = getRec(1, "name1"); // s="ok"
也可以使用
getColIndex和getRowIndex得到rowindex 和 colindex再使用
getRecFromIndex获得表值,注意检查index不可以超出范围(columns()和rows())
对于keyid不唯一的表,需要使用
getRowIndex获得rowindex
getColIndex获得colindex
再由getRecFromIndex得到需要的表值
同样注意检查index的范围!
\endcode
*/
class csvtable
{
public:
csvtable();
//! 初始化
/*!
\param filename 文件名
\param table_type 表文件类型,0:具有唯一id索引的表 1:索引id不唯一,需要联合另外一个field来用
\param fcb1 libcsv的cb1函数
\param fcb2 libcsv的cb2函数
\return 成功返回0 失败返回<0
*/
int Init(const char* filename, int table_type = 0, void (*fcb1)(void *, size_t, void *) = cb1, void (*fcb2)(int, void *) = cb2);
//! 检查col_index是否合法
bool check_columns(size_t index) const
{
if (index > (columns()-1)) return false;
return true;
}
//! 检查row_index是否合法
bool check_rows(size_t index) const
{
if (index > (rows()-1)) return false;
return true;
}
//! 按表keyid值和col_name得到表值,适用于唯一id索引表
/*!
当查表获得某个值时用这个,如果需要获得同一行的多个值,最好使用getRecFromIndex进行遍历而不是用这个函数遍历
*/
const std::string& getRec(int keyid, const std::string& col_name) throw(std::string)
{
// if (table_type != 0) throw("use wrong function! table_type!=0 ");
return getRec(keyid, getColIndex(col_name));
}
//! 按表关键字查col_index处的表值,只适用于唯一id索引表
const std::string& getRec(int keyid, int col_index) throw (std::string)
{
if (table_type != 0) throw("use wrong function! table_type!=0 ");
if (check_columns(col_index)==false) throw(std::string("getRec check failed."));
int ri = getRowIndex(keyid);
// if (check_rows(ri)==false) throw("getRrec check row failed");
return (*((keylist[ri])+col_index));
}
//! 由行列index得到表值
const std::string& getRecFromIndex(int RowIndex, int ColIndex)
throw(std::string)
{
// 一般来讲,RowIndex不会出错,所以没有检查RowInex
if (check_columns(ColIndex)==false)
throw(std::string("getRecFromIndex check failed"));
return (*(keylist[RowIndex]+ColIndex));
}
//! 由表头col_name得到col_index
int getColIndex(const std::string& col_name) throw (std::string)
{
std::map< std::string, int >::iterator pos;
pos = titlemap.find(col_name);
if (pos != titlemap.end())
{
return pos->second;
}
throw(std::string("getColIndex not found:")+std::string(col_name));
}
//! 由keyid和aux_keyid两个表值确定rowindex
/*!
\param keyid 表关键索引id值
\param aux_col_index 辅助列col的索引值,由getColIndex得到
\param aux_keyid 辅助关键索引id值
对应普通表,aux_keyid缺省为-1,此时只由keyid确定rowindex,对于aux_keyid不为-1的时候,从索引id不唯一的表中查找
*/
int getRowIndex(int keyid, int aux_col_index = -1, int aux_keyid = -1) throw (std::string )
{
// 需要检查表类型和aux_keyid是否匹配
// 普通表
if (table_type ==0 && aux_keyid == -1)
{
HashMap::iterator pos;
pos = keyindexmap.find(keyid);
if (pos != keyindexmap.end())
{
return pos->second;
}
throw(std::string("getRowIndex failed"));
}
else if (table_type ==1 && aux_keyid > -1 && aux_col_index > -1)
{
std::pair<HashMultiMap::iterator, HashMultiMap::iterator> itpair =
keyindexmultimap.equal_range(keyid);
for (; itpair.first != itpair.second; ++itpair.first)
{
// itpair.first->second 为rowindex
if (aux_keyid ==
atoi(getRecFromIndex(itpair.first->second
, aux_col_index).c_str()))
return itpair.first->second;
}
throw(std::string("getRowIndex 2 failed"));
}
// run here , there must something wrong.
throw (std::string("table_type and aux_keyid not match or aux_keyid out of range!"));
}
//! 得到keyid的所有行索引
/*!
\param keyid 表关键索引id值
\param vecIndex 返回所有行索引
*/
int getRowSIndex(int keyid, std::vector<int>& vecIndex) throw (std::string)
{
// 需要检查表类型和aux_keyid是否匹配
// 普通表
vecIndex.clear();
if (table_type == 0)
{
HashMap::iterator pos;
pos = keyindexmap.find(keyid);
if (pos != keyindexmap.end())
{
vecIndex.push_back(pos->second);
return 1;
}
throw(std::string("getRowIndex failed"));
// return 0;
}
else if (table_type == 1)
{
std::pair<HashMultiMap::iterator, HashMultiMap::iterator> itpair =
keyindexmultimap.equal_range(keyid);
if (itpair.first == itpair.second)
{
throw(std::string("getRowIndex 2 failed"));
}
for (; itpair.first != itpair.second; ++itpair.first)
{
vecIndex.push_back(itpair.first->second);
}
return vecIndex.size();
}
throw (std::string("table_type and aux_keyid not match or aux_keyid out of range!"));
}
//! 读取csv数据文件
/*!
* \param zSql 一條sql語句
* sucess:0 error:<0
*/
int read(const char* zSql=0);
virtual ~csvtable();
//! field计数
void fields_count()
{
_fields++;
}
//! 返回field计数
size_t fields() const
{
return _fields;
}
//! row计数
void rows_count(int adj=1)
{
_rows += adj;
}
//! 返回總行数
size_t rows() const
{
return _rows;
}
//! 设定列数
void set_columns(size_t c)
{
_columns = c;
}
//! 返回列数
size_t columns() const
{
return _columns;
}
//! 设置表头标志
void settitle(bool t)
{
_btitle = t;
}
//! 是否已经分析完表头
bool havetitle() const
{
return _btitle;
}
//! 输出csv表头信息和内容
friend std::ostream& operator <<(std::ostream&, csvtable&);
std::map< std::string, int > titlemap; ///< 表头index映射
std::vector< std::string* > keylist; ///< 表索引链,用vector省点事吧
size_t cur_col; ///< cb1函数保存数据索引用
//! 显示文件名
std::string name() const
{
return _filename;
}
private:
std::string _filename; // 文件名
int table_type; // csv文件表类型 0:普通表,有唯一索引id值 1:索引id值不唯一
size_t _fields; // 数据总个数
size_t _rows; // 总行数
size_t _columns; // 列数 columns = fields / rows
bool _btitle; // 标志表头读了没有啊
void (*fcb1)(void*, size_t, void*); // cb1函数指针
void (*fcb2)(int, void*); // cb2函数指针
struct csv_parser _parser;
unsigned char _options; // csv分析选项
// 关键字索引map
/*
key为表索引的id值, value为数组下标,这个下标对于keylist的下标
*/
HashMap keyindexmap;
HashMultiMap keyindexmultimap; // 表索引id值不唯一,用这个建立索引map
int createindex(const char* zSql); // 建立索引id的map
#ifdef USE_SQLITE3
sqlite3* db; // 库对象
#endif
};
#endif
--------------------------------------------------------------------------------------------
/*! \file csvtable.cpp
fileencoding:utf-8
\brief 读取csv文件函数实现
\author
\date
*/
#include <fstream>
#include <sstream>
#include <iostream>
#include <cstring>
#include "csvtable.h"
void cb1(void* s, size_t len, void* data)
{
csvtable* ct = (csvtable*)data;
ct->fields_count();
std::string str((char*)s, len);
// std::cout<<"cb1:"<<len;
if (!ct->havetitle())
{
// 处理titlemap
// std::cout<<" cb11:"<<str<<"\n";
ct->titlemap.insert(std::make_pair(str,ct->cur_col++));
}
else
{
// 首先检查游标
if (ct->cur_col == ct->columns())
{
ct->cur_col = 0;
}
// std::cout<<" cur_col="<<ct->cur_col<<" cb12:"<<str<<'\n';
// 赋值
*((ct->keylist[ct->keylist.size()-1])+ct->cur_col) = str;
// std::cout<<*((ct->keylist[ct->keylist.size()-1])+ct->cur_col)<<std::endl ;
ct->cur_col++; // 最后移动游标
}
}
void cb2(int c, void* data)
{
csvtable* ct = (csvtable*)data;
ct->rows_count();
// std::cout<<"cb2\n";
if (!ct->havetitle())
{
// csv表结构第一行是cloumn name 所以去掉這一行的計數
ct->rows_count(-1);
// 第一次执行cb2,此时的field计数就是列数
ct->settitle(true);
ct->set_columns(ct->fields());
}
ct->keylist.push_back(new std::string[ct->columns()]);
// std::cout<<"new"<<ct->keylist.size()<<std::endl;
}
#ifndef USE_SQLITE3
static int is_space(unsigned char c)
{
if (c == CSV_SPACE || c == CSV_TAB) return 1;
return 0;
}
static int is_term(unsigned char c)
{
if (c == CSV_CR || c == CSV_LF) return 1;
return 0;
}
#endif
csvtable::csvtable()
{
_fields = 0;
_rows = 0;
fcb1 = 0;
fcb2 = 0;
_options = 0;
_btitle = false;
cur_col = 0;
#ifdef USE_SQLITE3
db = 0;
#endif
}
// 释放资源
csvtable::~csvtable()
{
// 释放keylist new出来的string数组
std::vector< std::string* >::iterator it;
for (it=keylist.begin(); it!=keylist.end(); ++it)
{
// std::string* p = *it;
delete [](*it);
}
}
#ifndef USE_SQLITE3
int csvtable::Init(const char* filename,
int table_type,
void (*fcb1)(void *, size_t, void *),
void (*fcb2)(int, void *))
{
if (filename == 0) return -1;
this->table_type = table_type;
this->fcb1 = fcb1;
this->fcb2 = fcb2;
_filename = filename;
// 检测文件是否存在
std::ifstream infile(filename);
if (!infile)
{
return -2;
}
if (csv_init(&_parser, _options) != 0)
{
return -3;
}
// 添加空白和结束符的定义
csv_set_space_func(&_parser, is_space);
csv_set_term_func(&_parser, is_term);
return 0;
}
int csvtable:: read(const char* zSql)
{
// 不可以重复读
if (havetitle())
return -6;
FILE *fp;
fp = fopen(_filename.c_str(), "rb");
if (fp)
{
const int readsize = 8192;
char line[readsize];
size_t len;
// magic word check
if (!fgets(line, readsize, fp))
{
return -1;
}
if (strncmp(line, "\"FCTB1.00",strlen("\"FCTB1.00")) != 0
&& strncmp(line, "\"\"\"FCTB1.00",
strlen("\"\"\"FCTB1.00")) !=0
&& strncmp(line, "FCTB1.00",
strlen("FCTB1.00")) !=0 )
{
std::cout<<"magic word check failed."<<std::endl;
return -2;
}
// ignore Chinese comment
if (!fgets(line, readsize, fp))
{
return -6;
}
/* 重点在这里*/
while ((len = fread(line, 1, readsize, fp)) > 0)
{
if (csv_parse(&_parser, line, len, fcb1, fcb2, this)!= len)
{
// error occur,立马挂掉
fprintf(stderr, "Error while parsing file: %s\n",
csv_strerror(csv_error(&_parser)));
exit(EXIT_FAILURE);
}
}
csv_fini(&_parser, fcb1, fcb2, this);
csv_free(&_parser);
fclose(fp);
// 列数检查
if (columns() != _fields / (_rows+1))
{
std::cout<<"Error! columns="<<columns()
<<" field="<<_fields<<" rows="<<_rows;
return -3;
}
// 删除最后一个分配的未使用存储
size_t size = keylist.size();
if (size>0)
{
std::string* p = keylist[size-1];
delete []p;
keylist.pop_back();
}
// 建立索引map
if (createindex(zSql)<0)
{
std::cout<<"createindex failed, return -4"<<std::endl;
return -4;
}
return 0;
}
return -5;
}
#else // USE_SQLITE3
int csvtable::Init(const char* filename,
int table_type,
void (*fcb1)(void *, size_t, void *),
void (*fcb2)(int, void *))
{
if (filename == 0) return -1;
this->table_type = table_type;
_filename = filename;
// 打开库文件
int rc = sqlite3_open_v2(filename, &db, SQLITE_OPEN_READONLY, 0);
if (rc)
{
std::cout<<sqlite3_errmsg(db)<<":"<<filename<<std::endl;
sqlite3_close(db);
return -2;
}
// 服务器就不要用加密了吧
// // sqlite3_key(sdb, passwd, strlen(passwd));
return 0;
}
int csvtable:: read(const char* zSql)
{
if (zSql ==0 || db ==0)
{
return -1;
}
// 不可以重复读
if (havetitle())
return -6;
// std::string zSql("select * from ");
// zSql.append(view_name);
// zSql.append(";");
// 准备
sqlite3_stmt* ppStmt; // Statement hanlde
int rc = sqlite3_prepare_v2(db, zSql, -1, &ppStmt, 0);
if (rc)
{
std::cout<<sqlite3_errmsg(db)<<std::endl;
std::cout<<zSql<<std::endl;
sqlite3_close(db);
return -3;
}
rc = 0;
while (1)
{
rc = sqlite3_step(ppStmt);
if (rc == SQLITE_DONE)
{
// csv表结构第一行是cloumn name
// sqlite查询没有这一行
// 为了和原来的写的代码兼容,这里多加一行
// rows_count();
break;
}
else if (rc != SQLITE_ROW)
{
std::cout<<"step return:"<<rc<<std::endl;
std::cout<<sqlite3_errmsg(db)<<std::endl;
sqlite3_close(db);
return -4;
}
rows_count(); // 行计数
int count = sqlite3_column_count(ppStmt);
if (!havetitle())
{
for (int i=0; i<count; i++)
{
std::string str = sqlite3_column_name(ppStmt, i);
titlemap.insert(std::make_pair(str,i));
}
settitle(true);
set_columns(count);
}
// 分配内存空间
keylist.push_back(new std::string[columns()]);
for (int i=0; i<count; i++)
{
fields_count(); // 计数
(*((keylist[keylist.size()-1])+i)).assign((char*)sqlite3_column_blob(ppStmt, i), sqlite3_column_bytes(ppStmt, i));
}
}
sqlite3_finalize(ppStmt); // 销毁处理语句对象
// 关闭
sqlite3_close(db);
// 行数检查
if (_rows == 0) // 没有数据
{
std::cout<<"Warning! "<<zSql<<" row="<<_rows<<" !\n";
return 0;
}
// 列数检查
if (columns() != _fields / _rows)
{
std::cout<<"Error! columns="<<columns()
<<" field="<<_fields<<" rows="<<_rows;
return -3;
}
// 建立索引map
if (createindex(zSql)<0)
{
std::cout<<"createindex failed, return -4"<<std::endl;
return -4;
}
return 0;
}
#endif
int csvtable::createindex(const char* zSql)
{
std::cout<<name()<<" "<<zSql<<"|createindex:"<<table_type;
switch (table_type)
{
// 唯一索引表,用hashmap
case 0:
{
for (size_t i=0; i<keylist.size(); i++)
{
keyindexmap.insert(std::make_pair(atoi((*keylist[i]).c_str()), i));
}
break;
}
// 不唯一索引,用hashmultimap
case 1:
{
for (size_t i=0; i<keylist.size(); i++)
{
keyindexmultimap.insert(std::make_pair(atoi((*keylist[i]).c_str()), i));
}
break;
}
default:
{
exit(EXIT_FAILURE);
}
}
std::cout<<" done\n ";
return 0;
}
std::ostream& operator <<(std::ostream& os, csvtable& ct)
{
os<<ct.name()<<"\ntotal columns="<<ct.columns()<<" rows="<<ct.rows()<<" field="<<ct.fields();
// 输出title
if (!ct.titlemap.empty())
{
os<<'\n';
std::map<std::string, int>::iterator it;
int i=0;
for (it=ct.titlemap.begin(); it!=ct.titlemap.end(); it++,i++)
{
os<<i<<':'<<it->first<<' ';
}
switch (ct.table_type)
{
case 0:
{ // index
HashMap::iterator pos;
os<<"\nkey:row index\n";
for (pos=ct.keyindexmap.begin(); pos!=ct.keyindexmap.end(); pos++)
{
os<<pos->first<<':'<<pos->second<<'\n';
}
// content
for (size_t key=0; key< ct.keylist.size(); key++)
{
os<<"row="<<key;
for (size_t j=0; j< ct.columns(); j++)
{
os<<" col="<<j<<" v="<<*(ct.keylist[key]+j);
if (j != ct.columns()-1)
os<<' ';
}
if (key != ct.keylist.size()-1)
os<<'\n';
}
break;
}
case 1:
{ // index
HashMultiMap::iterator pos;
os<<"\nmulti key:row index\n";
for (pos=ct.keyindexmultimap.begin(); pos!=ct.keyindexmultimap.end(); pos++)
{
os<<pos->first<<':'<<pos->second<<'\n';
}
// content
for (size_t key=0; key< ct.keylist.size(); key++)
{
os<<"row="<<key;
for (size_t j=0; j< ct.columns(); j++)
{
os<<" col="<<j<<" v="<<*(ct.keylist[key]+j);
if (j != ct.columns()-1)
os<<' ';
}
if (key != ct.keylist.size()-1)
os<<'\n';
}
break;
}
default:
break;
}
}
return os;
}
对象实体和初始化
//! 技能升级加点消耗表
csvtable TSkillUpConsume;
struct STData
{
class csvtable& table; ///< 實例
const char* filename; ///< 數據所在文件名稱
int table_type; ///< 數據表類型0或1
const char* zsql; ///< 生成數據表對應的sql查詢語句
};
STData DataTables[] =
{
{TSkillUpConsume,DATAFILE,0, "select * from b_repair;"},
.... // 这里添加各个表信息
};
// 初始化各种表对象
int InitDataTables(std::string path)
{
if (path[path.size()-1]!='/')
path.push_back('/');
for (size_t i=0; i<sizeof(DataTables)/sizeof(STData); i++)
{
std::string fullname = path+DataTables[i].filename;
int ret = DataTables[i].table.Init(fullname.c_str(), DataTables[i].table_type);
if ( ret != 0)
{
// 初始化有问题,直接挂掉
errf<<ret<<" Init,InitDataTable "<<fullname<<" "<<DataTables[i].zsql;
exit(EXIT_FAILURE);
}
ret =DataTables[i].table.read(DataTables[i].zsql);
if ( ret != 0)
{
// 读表问题,直接挂掉
errf<<ret<<" read,InitDataTable "<<fullname<<" "<<DataTables[i].zsql;
exit(EXIT_FAILURE);
}
debugf<<"Read "<<fullname<<" "<<DataTables[i].zsql<<" OK.";
}
return 0;
}
- 数据库(2):配置数据的缓存建立方法,建立通用表模型
- 数据库(1):配置数据的缓存建立方法,独立数据表模型
- laravel中常用的命令(路由列表、建立模型、建立数据迁移文件、注册中间件、 清除缓存)
- PowerDesigner建立数据库模型
- 通用方法:用建立Excel对象的方法来导出数据
- 建立对象模型方法
- 通用链表的建立和使用
- 使用MySQL Workbench建立数据库,建立新的表,向表中添加数据
- 配置数据引擎(BDE、SQL Link)的简单方法 /制做快速按钮条的方法/建立临时表的方法
- SQL2000数据库建立方法
- 数据库同义词建立方法
- 使用PowerDesigner建立数据库模型
- PowerDesigner系列: 建立数据库模型
- 使用PowerDesigner建立数据库模型
- 使用PowerDesigner建立数据库模型
- 使用PowerDesigner建立数据库模型
- 使用PowerDesigner建立数据库模型
- 使用PowerDesigner建立数据库模型
- fastcgi_finish_request
- 从零开始快速搭建Android应用自动化测试(二)
- 基于Zookeeper的服务注册与发现
- Mybatis3源码分析(06)-加载Configuration-缓存配置加载
- QQ公众号如何获取接口调用凭据
- 数据库(2):配置数据的缓存建立方法,建立通用表模型
- base64转码
- leetcode -- Repeated DNA Sequences -- 简单但要注意
- aerospike init
- 连接javascript
- Excel万能函数--Text
- /var/spool/clientmqueue下文件清理和产生
- 关于Certificate、Provisioning Profile、App ID的介绍及其之间的关系
- bzoj首