基于MySQL數據庫的論壇設計方案
基于MySQL數據庫的論壇設計方案
1。系統(tǒng)架構:
采用模塊化思想,分為3層:
a。數據存儲層:使用MySQL來存放bbs的所有數據,包括用戶信息,文章數據,用戶信件,用戶消息,系統(tǒng)數據(?),關鍵問題: 數據庫的規(guī)劃,是否用文件來輔助。
b。系統(tǒng)功能層:完成bbs的基本功能,由多個并列模塊組成,向下調用mysql的函數訪問數據庫,向上,接受處理請求,將處理的結果返回上層,根據請求類型,返回成敗結果和其他數據。而且模塊高度靈活,可以方便的修改增加。包括:
** 用戶模塊,處理用戶的注冊,基本數據的修改,權限的變化,網友信息的查詢。
** 版面模塊,完成文章發(fā)表,文章的讀取,文章的刪除,文章的加標記,讀改刪權限檢查,此模塊對數據庫的要求最高。
** 精華區(qū)模塊,包括精華區(qū)的文章,目錄的增加,刪除,上下移動
?。??)讀改刪權限檢查,目錄結構是其中的難點。
** 信件模塊,包括發(fā)新信件,讀刪信件,信箋標記,新信件的通知
** 消息模塊,包括發(fā)送消息,接受消息,新消息通知,消息回顧,消息存信件。
** 系統(tǒng)動態(tài)模塊,包括當前上站人數,當前動態(tài),由于變動頻繁,此類數據用共享內存實現(xiàn)可能更好。
** 聊天模塊,雙人聊天是否能借鑒icq的做法,由雙方直接通話,但聊天結果存信件可能較麻煩,同時,為兼容telnet功能,當上層服務層為telnet時,增加專門的模塊來進行處理。
** 聊天室模塊,利用共享內存還是數據庫?開房間,里面的權限問題。根據需要,還能增加新的功能。例如:活動看板模塊,但對于非telnet終端,意義好象不大。。。。。
3。數據庫設計
關鍵還是MySQL的效率問題,合理分配mysql的內存,特別是table cache的
大小。另外,當系統(tǒng)突然掉電呢?mysql是否robust?
table的名字設計,采用一位前綴表明類型,全部用小寫表示(?),例如:
系統(tǒng)的數據庫,以s為前導,如用戶表:suser(sUSER 呢?),具體如下:
s :系統(tǒng)表,suser,sclass
m :用戶信件表,msysop,mdrangon
w :用戶消息表,wsysop,wdrangon
a :版面索引表,aLinux,acampus
b :版面文章表,blinux,bcampus
c :特殊分類版面表,cnewboard
i :精華區(qū)索引表,ilinux,ilinux01,icampus,icampus04
j :精華區(qū)文章表,jlinux,jcampus,
另外,是使用字串還是數字作為標識呢?例如,一個叫sysop的帳號,其
id是1,他的信的表是msysop還是m00001呢?同樣,一個叫campus的版,對應的
代碼是5,則這個版的文章的表名是bcampus還是b00005呢?可能用字串會容易
理解,查錯吧。
用戶信息表:suser
usernum int unique, // 唯一標識符,最多30000個帳號,會不會太少了?
userid char[20] primary key, // 排序的關鍵字,id,全小寫。
passwd char[20], // 密碼,存放加密后的密文。
realid char[20], // 實際id,大小寫混合。
username char[24], // 用戶的泥稱
userlevel longint, // 64種權限?
nUMLogins int,
numposts int,
firstlogin time,
lastlogin time,
staytime time, /* 總共停留時間 */
lasthost char[32],
email varchar[100],
address varchar[100],
// 還需要其他數據嗎?是否需要留出一定的保留值,以后alter table來
// 增加新的字段時,效率如何?
版面分類表:sclass
classnum int unique, // 分類標識
classid char[20], // 分類的英文id:computer
classname varchar[100],// 分類的中文描述:電腦世界
classtable char[20], // 特殊分類對應的版面表
// 一般來說,每個版面只屬于一個分類,對于特殊分類,例如拳頭版塊, #p#page_title#e#
// 新版面,可以用專門的表來描述
版面表:sboard
boardnum int unique, // 版面的標識(需要嗎?)
boardid char[20], // 版面的英文名
boardname varchar[100], // 版面的中文名
boardclass char[20], // 版面所屬分類
boardsysop varchar[100], // 斑竹名單
boardposts int, // 版面的文章數
boardlevel int, // 版面的讀寫權限
indextable char[20], // 版面對應的索引表的名稱:aboardid?
texttable char[20], // 版面對應的文章表名稱: bboardid?
// 最后兩項有沒有必要出現(xiàn),是否可以作為必然對應關系,還是允許
// 出現(xiàn)更大的靈活性?另外版面的大小寫問題是否可以直接默認
// 只開頭字母大寫,
特殊分類版面表:snewboard, sstarboard
boardid char[20], // 版面的id
// 這樣的表有必要嗎?
版面索引表:acampus,aLinux,afootball。。。。。。
id int, // 文章序數,要手動調整????
mark char[1], // 文章標記,m,g,b,d。。。。
title varchar[100], // 文章標題
writer char[20], // 文章作者id
posttime time, // 發(fā)表時間
textnum longint, // 對應的編號???不調整
版面文章表
textnum longint, // 文章編號?
textword text, // 文章內容?
// 有必要將索引和文章內容分開嗎?從效率上看,況且lazy flush
// 是必然的。刪除也是先做個標記。
// 用戶中的版面文章是否未讀的數據比較繁,是否應該再建一堆的表
// 才能實現(xiàn)呢?
// 投票功能暫不考慮。。。。
4。用戶模塊設計
對于底層數據庫,調用MySQL的C API函數來進行數據庫的修改,內部保存一定的狀態(tài)變量(例如用戶名,還是留給上一層完成?),對上一層,則提供用戶管理的接口。
Class UserManage {
private:
char myuserid[20]; // 用戶的id,未登陸前為空
time logintime; // 用戶登陸時間,并用于計算停留時間
char loginhost[20]; //上站地點。
public:
int NewUser( char *userid, char *passwd );
新建一個用戶,判斷是否已經有,其他資料暫時為空,
firstlogintime,權限等設缺省值。
int UserLogin( char *userid, char *passwd );
用戶登陸,驗證密碼,
int ChangePasswd( char *oldpasswd, char *newpasswd );
修改密碼,要求原密碼一致。
int ChangePriData( char *newname, char *newemail,
char *newaddr );
改變基本數據,泥稱,email,住址。。。。
int ModifyNumData( int addlogin, int addpost );
修改文章數,上站次數,等數據。。。。注意調用對象。
int UserLogout();
用戶退出,修改lastlogin,staytime,loginhost等
// 普通查詢命令
int QueryCommonData( const char * userid, int& loginnum,
char * username, int& postnum,
time& lastlogin, char *lasthost );
查詢網友基本信息。
// 特權指令,函數在完成功能前,先判斷權限。
int QueryPriData( const char * userid, char *email,
char *addr );
查詢基本信息,普通人只能查自己,有特權才能查其他人。
int ModifyUserLevel( BOOL isAdd, unsigned long level );
修改用戶的權限,
int ModifyUserId( char *oldid, char *newid );
char *newemail, char *newaddr );
修改用戶的基本數據。
int ModifyUserNumdata( char *userid, int addlogin, int addpost );
修改用戶的文章數等數據。
int ModifyUsERPasswd( char *userid, char *newpasswd );
修改用戶的密碼。
}
以上各個函數難度不大,都是執(zhí)行相應的sql語句,訪問mysql數據庫,是否將一般指令歸到特權指令中去呢?權限的檢查,是放在這一層還是上一層? #p#page_title#e#
這更多的是看考慮的著重點,是看程序的清晰性還是代碼的簡練,可能還是看代碼吧,畢竟要考慮訪問量,另外,上層服務層是否也應該考慮權限檢查問題呢?
5。版面模塊設計
所謂分類,更多的是為telnet服務端考慮的,在cq66模式下,用戶可以按照自己的意愿進行分類,反正最后都是直接以版為基本單位訪問的。
對于版面文章的訪問,存放的時候以整篇文章為參數,文章的分塊由本層完成,如果上層以塊為單位傳送,則在上層全部傳完,組合后,再傳參到本層分解;在讀取 的時候,本層則以塊為單位訪問,如果上層要以全文為單位訪問,則在上層做合并 工作,本層不管。
至于要不要獨立出索引,不影響上層的操作,主要和下層的數據庫構造有關,主要考慮可行性,效率需求等。
權限的檢查放在哪里進行呢?還是放在上層吧,其實就telnet服務器端,和cq66 的客戶端,根本不會給一般用戶顯示特殊指令的菜單,當然,用戶可以直接發(fā)送cq66 的指令,服務器方還是要檢查的。但應該不用在它下面的功能模塊層再檢查一次吧 。
Class BoardManage {
private:
public:
// 有關分類的操作
int GetClassNameInfo( int maxclass, char **classid,
char ** classname );
返回分類的信息,中英文名。
int GetBoardName( int maxboards, char *classid,
char **boardname );
返回某分類中的版面信息,一般分類,直接select ..
from sboard
where boardclass == .... 特殊分類則查相應的表。。。。
// 修改需要版面管理員以上的特權
int NewClass( char * newclassname, int type );
新建分類,普通分類還是特殊分類,
int DeleteClass( char *newclassname );
刪除分類,但不cascade,即本層不負責一致性,由上層負責將
相應的版面的分類信息改為別的。分類改名也是先刪再建,
int AddClassBoard( const char *classname, char *newboardname );
將已建好的版加入某分類中,專門針對特殊分類,對一般分類,其
效果和modifyboardinfo一樣,
int DeleteClassBoard( const char *classname, char *boardname );
從分類中刪除某個版,也是針對特殊分類,對一般分類,效果也
是和modifyboardinfo一樣,一個版的分類屬性可以為空,即不屬
于任何分類。
// 有關版的信息的操作。
int NewBoard( const char *boardid,char *boardname);
新建一個版,建立對應的表。其他參數取默認值。
int DeleteBoard( const char *boardid );
刪除一個版,刪除對應的表。
int GetBoardInfo( const char *boardid, char *boardname,
int& numposts, char *masters, char *class,
long &level );
取的版面的信息。
int ModifyBoardId( const char *oldid, char *newid );
改變版的英文id,對應table的名稱也要改變,
int ModifyBoardInfo( const char *boardid, char *boardname,
int numposts, char *masters, char *class,
long level );
修改版面信息,需要特權。
// 有關版面文章的操作。
int AddText( char *boardid, char *title, char *writer,
char *text );
往版面中增加文章,內部將長文章分割成2k的塊。
int DeleteText( char *boardid, int num );
刪除文章,只是做一個標記,并不立刻修改對應的table。
int FlushTable( char *boardid );
刷新版面,刪除被刪文章的對應的記錄。
int MarkText( char *boardid, int num, char mark );
給文章做標記。
int ModifyTitle( char *boardid, int num, char *newtitle );
修改文章的標題。
int ModifyText( char *boardid, int num, char *newtext );
修改文章內容,不是自己的文章需要特權。
int GetTextInfo( const char *boardid, int num, char *title,
char *writer, char& mark );
取得文章的標題信息。 #p#page_title#e#
int GetText( const char *boardid, int num, int block,
char *text );
讀取文章的內容,以塊為單位。
// 文章和作者的查詢
// 一次將查詢的結果全部返回?
int QueryWriter( const char *boardid, char *writer,
char **result );
查詢版面上,某作者的文章。
int QueryTitle( const char *boardid, char *title,
char **result );
查詢版面上,標題中包含指定內容的文章。
}
參數的傳遞是一件比較討厭的事,從抽象的角度,希望返回的數據與底層無關,所以應該加以處理,但從效率的角度,又不希望數據進行多次復制,另一方面,空間的申請釋放,究竟是在上層中完成還是在本層中完成呢?一不小心,很容易有內存錯誤。