這里的文字主要是為了記錄下我的一些思路,以防日后遺忘。中途會經歷相當多的修改。有興趣的朋友歡迎指教。
關于我的網站應該提供一些什么樣的功能、使用什么樣的用戶交互方式,雛形在我的腦中基本已經形成了,但是還不系統。我需要趕快把它們記錄下來,免得以后忘了。當然,在開發的過程中,我的思路隨時都會發生變化,因此這里記下的東西也會發生很多修改。一想到網站的功能,馬上就會想到要設計什么樣的數據庫來支持它。所以,這里的記錄主要是怎么設計數據庫。
數據庫軟件使用MySQL,先修改my.ini配置文件,默認使用UTF-8編碼、InnoDB數據庫引擎,并啟動二進制日志,以使得數據庫備份的工作變簡單些。
datadir = " D:/MySQL_Data/ "
innodb_data_home_dir = ./ibdata
innodb_log_group_home_dir = ./ibdata
innodb_data_file_path = ibdata1:50M:autoextend:max:1G
log-bin = ./bin_log/binlog
binlog-do-db = YumDaysIndex
binlog-do-db = YumDays001
然后開始創建數據庫,經過前面在網站架構方面的設想,我需要創建最少兩個數據庫:一個索引數據庫,一個或多個內容數據庫。我把索引數據庫命名為YumDaysIndex,內容數據庫命名為YumDaysNNN,其中的NNN是數字編號,在剛開始的時候,肯定只要一個YumDays001就夠了。
GRANT ALL PRIVILEGES ON YumDays001.* TO '********'@'%' IDENTIFIED BY '********' WITH GRANT OPTION;
CREATE DATABASE YumDaysIndex;
CREATE DATABASE YumDays001;
選擇YumDays001數據庫,創建用戶表:
CREATE TABLE users(
id char(32) NOT NULL PRIMARY KEY,
name varchar(30) NOT NULL,
password char(32) NOT NULL,
monicker varchar(30) NOT NULL,
question varchar(30) NOT NULL,
answer varchar(30) NOT NULL,
email varchar(30) NOT NULL,
qq varchar(12) NOT NULL,
roleid char(32) NOT NULL,
score int NOT NULL DEFAULT 0,
albumusage int NOT NULL DEFAULT 0,
regtime timestamp NOT NULL DEFAULT '2008-01-01 00:00:00',
logintime timestamp NOT NULL DEFAULT '2008-01-01 00:00:00',
isdeleted varchar(2) NOT NULL DEFAULT '0',
INDEX(name),
INDEX(monicker)
);
這樣一些字段分別代表ID、用戶名、密碼、昵稱、密碼問題、答案、email、QQ號、用戶角色、積分、相冊已經使用的磁盤空間、注冊時間、登錄時間、是否刪除等。設計這個表的思路如下:
1、name只能用英文,因為它將是URL的組成部分,為了便于用戶之間的識別,所以需要monicker(昵稱)字段;
2、根據用戶的score字段可以算出用戶的相冊容量,每次上傳圖片的時候,都增加albumusage字段的值,如果空間已經被使用完,則不容許上傳;
3、ID使用UUID類型,所以它的列類型為char(32),之所以使用UUID,是因為users表會被分割到很多個數據庫中,使用UUID可以保證ID的唯一性;
4、isdelete的列類型也比較奇怪,為varchar(2),而默認值卻是'0'(字符串),這是因為SpringSide的實現中,在刪除數據的時候,會把這個字段設置為'-1'(字符串)。
從這個表中可以看出,這里涉及到一個用戶角色的問題,不同的角色擁有不同的權限,所以需要一個Roles表。考慮到Roles表包含的記錄數不會太多,而且分布到多個服務器上也不好維護,所以Roles表應該放到索引服務器中。用戶登錄這樣的過程也應該由索引服務器處理,然后將用戶的一些信息保存到Cookie中,不過如果用戶操作的時候需要查看權限,則一定要向索引服務器請求,索引服務器通過提供WebService來響應請求,因為在Cookie中保存權限會出現安全問題。
創建Roles表的代碼如下:
CREATE TABLE roles(
id char(32) NOT NULL PRIMARY KEY,
name varchar(20) NOT NULL,
privilegesflag varchar(255),
INDEX(name)
);
這里需要說明的是privilegesflag字段,該字段我設計為一個用逗號隔開的字符串,比如“post,reply”,代表用戶具有發帖、回帖的權限。這么設計的好處就是在開發過程中,不用為了增加權限而修改數據表的結構,只用往這個表中加入新的字符串就行了,而Java代碼中,分割字符串又是那么的方便。
在這個表中,我初步設計的角色有四個,它們分別是管理員、超級用戶、普通用戶和被鎖定用戶。當然,如果網站規模越來越大,需要有人幫著把關時(否則肯定黃帖廣告貼泛濫),可能需要版主、編輯這樣的角色。
在我剛開始設計這個系統時,本來是加入了用戶群組的功能的,但是經過這兩天的沉淀,我決定暫時還是不要這個功能了。以后再加上都可以,但是開發初期我不想為自己找太多麻煩。
文章要進行分類,因此需要創建一個分類表,這個表依然保留在索引服務器上:
id char(32) NOT NULL PRIMARY KEY,
name varchar(20) NOT NULL,
INDEX(name)
);
這個表的內容很簡單,無需解釋。
再下面,就是用來保存文章的表了:
CREATE TABLE topics(
id char(32) NOT NULL PRIMARY KEY,
catalogid char(32) NOT NULL,
subject varchar(60) DEFAULT NULL,
content text,
summary varchar(300) default NULL,
mainpicture varchar(100) NOT NULL,
userid char(32) NOT NULL,
time timestamp NOT NULL default CURRENT_TIMESTAMP,
lastedittime timestamp NOT NULL default '2007-01-01 00:00:00',
lastreplytime timestamp NOT NULL default '2007-01-01 00:00:00',
visitcount int NOT NULL,
accessmod tinyint NOT NULL,
INDEX(subject),
INDEX(userid),
INDEX(time),
INDEX(lastreplytime)
);
該表應該保存到內容數據庫中。其中的字段都很好理解,從名字即可看出意義。其中需要解釋的兩個字段如下:
1、mainpicture:我希望每一篇文章都有一個主題圖片,該圖片在顯示文章列表的時候也可以顯示(當然是縮略圖)。其內容是一個URL。
2、accessmod:該字段保存了該文章的安全屬性,即是否公開。取值為1則不公開,取值為3則完全公開。那么2呢?那是我為用戶群保留的,取值為2則只正對該文章所屬的群公開。
至于索引,那是要根據網站需要提供什么樣的功能來設計的。當網站需要按照哪一個規則對文章進行查找的時候,就要在該字段上建立索引,以便加快查找速度。
再往下,則是用來保存回復的表:
id char(32) NOT NULL PRIMARY KEY,
subject varchar(50) NOT NULL,
content text,
userid char(32) NOT NULL,
time timestamp NOT NULL default CURRENT_TIMESTAMP
);
自己回復了哪些文章,心里也要有個數,所以要建立一個表,用來記錄用戶參與了的文章:
id char(32) NOT NULL PRIMARY KEY,
userid char(32) NOT NULL,
topicid char(32) NOT NULL,
INDEX(userid)
);
再然后,是用來管理相冊和相片的表:
id char(32) NOT NULL PRIMARY KEY,
userid char(32) NOT NULL,
name varchar(20) NOT NULL,
description varchar(200) DEFAULT NULL,
photopath varchar(30) NOT NULL,
miniphotopath varchar(30) NOT NULL,
accessmod tinyint NOT NULL,
INDEX(userid)
);
這里的photopath是該相冊在服務器上的文件路徑,而miniphotopath則是縮略圖的路徑。accessmod也是起安全控制作用的,意義同前。
id char(32) NOT NULL PRIMARY KEY,
albumid char(32) NOT NULL,
filename varchar(20) NOT NULL,
INDEX(albumid)
);
這樣,內容數據庫的表已經差不多了,剩下的在開發過程中再逐步完善。而索引服務器還只有前面提到的Roles表和Catalogs表,但是索引服務器要提供顯示首頁的功能,要提供反向代理的功能,要提供統計排序的功能。因此,我在索引數據庫中設計了以下表。
首先,索引服務器中也應該保存有Users的所有數據,需要保存所有的記錄,但是不需要保存所有的字段。初步的設計如下:
CREATE TABLE users(
id char(32) NOT NULL PRIMARY KEY,
name varchar(30) NOT NULL,
password char(32) NOT NULL,
monicker varchar(30) NOT NULL,
roleid char(32) NOT NULL,
score int NOT NULL DEFAULT 0,
webserver varchar(10) NOT NULL,
INDEX(name),
INDEX(score)
);
這里保存有用戶的驗證信息,因此簡單的驗證功能都可以通過索引服務器來完成。這里有兩個字段值得一提,一是score,用來保存用戶的分數,主要是為了實現用戶排名;另一個字段是webserver,它保存了該用戶會被分配到那個Web服務器。
索引服務器還應該保存所有Topics的記錄,當然,它不需要保存所有的字段,和Users表一樣,它只需要知道到哪個Web服務器可以找到這個Topic的所有數據就行了。初步設計如下:
id char(32) NOT NULL PRIMARY KEY,
catalogid char(32) NOT NULL,
time timestamp NOT NULL default CURRENT_TIMESTAMP,
webserver varchar(10) NOT NULL,
INDEX(time)
);
這個表非常簡單,只是維護了一個所有Topic的索引而已,通過webserver字段就知道到哪里找它的詳細信息,索引服務器顯示主頁的時候,可以通過AJAX調用相應的webserver來顯示它的摘要信息。time字段是用來排序的,catalog字段是用來分類的。
我還有一個想法,就是想能夠按照最新的回復來對Topic進行排序,基本上所有的論壇都是采取的這種方法,只需要有人回復,文章就會被頂上去。但是,由于Topics是分布存儲的,所以需要有一個表用來保存最近被回復的文章的信息,而其它的服務器則可以通過定時服務,每隔幾分鐘在自己的服務器上統計最新被回復的文章,然后提交到索引服務器。其結構如下:
id char(32) NOT NULL PRIMARY KEY,
subject varchar(60) NOT NULL,
lastreplytime timestamp NOT NULL default '2007-01-01 00:00:00',
sebserver varchar(10) NOT NULL,
INDEX(lastreplytime)
);
這個表,只需要保存少量的紀錄就夠了。
還要一個統計表,維護一些統計信息,如注冊用戶數、文章總數、回復總數、響應新用戶注冊的當前服務器等等,如下:
usercount int NOT NULL,
topiccount int NOT NULL,
replycount int NOT NULL,
currentwebserver varchar(10) NOT NULL
);
這個表的名字是單數形式,因為這個表只需要一條紀錄就夠了。
索引服務器還需要維護所有的相冊信息,同Topics表一樣,其結構如下:
id char(32) NOT NULL PRIMARY KEY,
time timestamp NOT NULL default CURRENT_TIMESTAMP,
webserver varchar(10) NOT NULL,
INDEX(time)
);
數據庫的設計到此告一段落,下一步就開始寫代碼了。數據庫設計中的缺陷,只有經過實戰的檢驗才能夠體現出來。