描述:分表建模,用于管理少量表,表多了建模型繁琐。
例子:
基础模型及表模型实例 (行数据对象)
// 基类接口 (主要提供要处理的接口)
template <typename T>
struct EntityBase
{
virtual string getTableName()=0;
virtual string getDBName()=0;
virtual string getPrimary()=0;
virtual string readDB()=0;
virtual void fromDB(MusicDbRow &aRow)=0;
virtual string toDB(list<T> &aDataSet)=0;
virtual string dump()=0;
virtual ~EntityBase(){}
};
// 例子
//公会名称数据
struct GonghuiInfo: public EntityBase<GonghuiInfo>
{
// 表模型
uint32_t contractid; //公会签约ID(主键)
string name; //公会名称
uint32_t createtime;//更新时间
//实现虚函数,声明相关配置操作
virtual string getTableName()
{
return "gonghui_table"; // 对应数据库的表名
}
virtual string getDBName()
{
return "activity_one"; // 数据库名字 (一个数据库可以直接写入基类)
}
virtual string getPrimary()
{
return toString(contractid); // 唯一键 (经常对应的是数据库里面的主键,如果是组合键这个地方就是组合键,用于map的key识别)
}
virtual string readDB()
{
string sql="SELECT contractid, name, createtime FROM "; // 从数据库读表的select语句
sql.append(TABLE_SD2015_GH);
sql.append(" ORDER BY createtime DESC");
return sql;
}
virtual void fromDB(MusicDbRow &aRow) // 获取数据行键入到模型
{
contractid=aRow[0].asUInt();
name=aRow[1].str;
createtime=aRow[2].asUInt();
}
virtual string toDB(list<GonghuiInfo> &aDataSet) // 从模型到数据表
{
string tSql="REPLACE INTO ";
tSql.append(TABLE_SD2015_GH);
tSql.append("(contractid, name, createtime) VALUES ");
for(list<GonghuiInfo>::iterator it=aDataSet.begin(); it!=aDataSet.end();)
{
GonghuiInfo &tInfo=(*it);
tSql+="("+yymusic::toString(tInfo.contractid)+", "
+"\""+tInfo.name+"\", "
+yymusic::toString(tInfo.createtime)+") "
;
++it;
if(it!=aDataSet.end()) tSql.append(", ");
}
return tSql;
}
virtual string dump() // 打印值
{
stringstream ss;
ss << "contractid:" << contractid
<< ",name:" << name
<< ",createtime:" << createtime
;
return ss.str();
}
};
模型数据组合器 (表数据对象)
template <typename T>
struct EntityTable
{
EntityTable(){}
// 从数据库中获取数据
bool load()
{
MusicDBContext dbContext(entity.getDBName(), HASH_ALL_DB_KEY, false); // 获取数据库连接对象
string ssql=entity.readDB();
if(!ssql.empty())
{
//执行失败才false
if(!dbContext.commonSqlExe(ssql.c_str())) return false; // 执行查找语句
MusicDbRow tRow;
map<string, T> tDataMap;
T tEntity;
while(dbContext.fetchRow(tRow))
{
tEntity.fromDB(tRow); // 将数据插入模型
tDataMap[tEntity.getPrimary()]=tEntity; // 将模型插入表对象
}
boost::mutex::scoped_lock lock(_mutex);
data.swap(tDataMap);
}
return true;
}
//更新表数据,允许部分更新,会立即更新本地缓存,同时通知其他进程从数据库加载全量。
bool set(list<T> &aDataSet)
{
if(!aDataSet.empty())
{
MusicDBContext dbContext(entity.getDBName(), HASH_ALL_DB_KEY, false);
string ssql;
ssql=entity.toDB(aDataSet); // 产生插入语句
if(!ssql.empty())
{
//执行失败才false
if(!dbContext.commonSqlExe(ssql.c_str())) return false; // 执行更改到数据库
boost::mutex::scoped_lock lock(_mutex);
for(typename list<T>::iterator it=aDataSet.begin(); it!=aDataSet.end(); ++it)
{
data[(*it).getPrimary()]=*it; // 更改缓存
}
}
}
return true;
}
void getData(map<string, T> &aDataMap)
{
boost::mutex::scoped_lock lock(_mutex);
aDataMap=data;
}
// 获取一个对象
void getOne(const string &aPrimary, T& aEntity)
{
boost::mutex::scoped_lock lock(_mutex);
if(data.find(aPrimary)==data.end()) return;
aEntity=data[aPrimary];
}
private:
boost::mutex _mutex;
map<string, T> data; // 表数据列表
T entity; // 模型对象
};
表管理器 (整合所有的表)
struct EntityManager
{
static EntityManager& getInstance()
{
static EntityManager oIns;
return oIns;
}
// 初始化数据表
template <typename T>
void initTable()
{
T tEtt;
EntityTable<T> *tTableMgr=new EntityTable<T>();
string tKey=tEtt.getDBName()+"_"+tEtt.getTableName(); // 数据库名+表名组合成表唯一key
boost::mutex::scoped_lock lock(_mutex);
data[tKey]=new EntityTable<T>();
}
// load数据到缓存
template <typename T>
bool loadTable(uint32_t aRetry=3, uint32_t aRetryInterval=500000)
{
T tEtt;
EntityTable<T> *tTableMgr;
{
string tKey=tEtt.getDBName()+"_"+tEtt.getTableName();
boost::mutex::scoped_lock lock(_mutex);
if(data.find(tKey)==data.end()) return false;
tTableMgr=(EntityTable<T>*)data[tKey];
}
if(tTableMgr->load()) return true;
// 容错重处理
for(uint32_t i=0; i<3; i++)
{
logth(Info, "EntityManager::loadTable retrying at %u time %u", i, aRetryInterval)
usleep(aRetryInterval);
if(tTableMgr->load()) return true;
}
return false;
}
//更新表数据,允许部分更新,会立即更新本地缓存,同时通知其他进程从数据库加载全量。
template <typename T>
bool setTable(list<T> &aDataSet, uint32_t aRetry=3, uint32_t aRetryInterval=500000)
{
T tEtt;
EntityTable<T> *tTableMgr;
{
string tKey=tEtt.getDBName()+"_"+tEtt.getTableName();
boost::mutex::scoped_lock lock(_mutex);
if(data.find(tKey)==data.end()) return false;
tTableMgr=(EntityTable<T>*)data[tKey];
}
if(tTableMgr->set(aDataSet)) return true;
// 容错重处理
for(uint32_t i=0; i<3; i++)
{
logth(Info, "EntityManager::setTable retrying at %u time %u", i, aRetryInterval)
usleep(aRetryInterval);
if(tTableMgr->set(aDataSet)) return true;
}
return false;
}
// 获取整个表数据
template <typename T>
void getTable(map<string, T> &aDataMap)
{
T tEtt;
EntityTable<T> *tTableMgr;
{
string tKey=tEtt.getDBName()+"_"+tEtt.getTableName();
boost::mutex::scoped_lock lock(_mutex);
if(data.find(tKey)==data.end()) return;
tTableMgr=(EntityTable<T>*)data[tKey];
}
tTableMgr->getData(aDataMap);
}
// 获取一个对象数据
template <typename T>
void getOne(const string &aPrimary, T& aEntity)
{
T tEtt;
EntityTable<T> *tTableMgr;
{
string tKey=tEtt.getDBName()+"_"+tEtt.getTableName();
boost::mutex::scoped_lock lock(_mutex);
if(data.find(tKey)==data.end()) return;
tTableMgr=(EntityTable<T>*)data[tKey];
}
tTableMgr->getOne(aPrimary, aEntity);
}
private:
map<string, void*> data;
boost::mutex _mutex;
~EntityManager()
{
}
};