為我的創(chuàng)業(yè)網(wǎng)站創(chuàng)建數(shù)據(jù)庫(kù)
Posted on 2008-01-24 22:05 京山游俠 閱讀(2621) 評(píng)論(6) 編輯 收藏 所屬分類(lèi): J2EE學(xué)習(xí)及探索這里的文字主要是為了記錄下我的一些思路,以防日后遺忘。中途會(huì)經(jīng)歷相當(dāng)多的修改。有興趣的朋友歡迎指教。
關(guān)于我的網(wǎng)站應(yīng)該提供一些什么樣的功能、使用什么樣的用戶(hù)交互方式,雛形在我的腦中基本已經(jīng)形成了,但是還不系統(tǒng)。我需要趕快把它們記錄下來(lái),免得以后忘了。當(dāng)然,在開(kāi)發(fā)的過(guò)程中,我的思路隨時(shí)都會(huì)發(fā)生變化,因此這里記下的東西也會(huì)發(fā)生很多修改。一想到網(wǎng)站的功能,馬上就會(huì)想到要設(shè)計(jì)什么樣的數(shù)據(jù)庫(kù)來(lái)支持它。所以,這里的記錄主要是怎么設(shè)計(jì)數(shù)據(jù)庫(kù)。
數(shù)據(jù)庫(kù)軟件使用MySQL,先修改my.ini配置文件,默認(rèn)使用UTF-8編碼、InnoDB數(shù)據(jù)庫(kù)引擎,并啟動(dòng)二進(jìn)制日志,以使得數(shù)據(jù)庫(kù)備份的工作變簡(jiǎn)單些。
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
然后開(kāi)始創(chuàng)建數(shù)據(jù)庫(kù),經(jīng)過(guò)前面在網(wǎng)站架構(gòu)方面的設(shè)想,我需要?jiǎng)?chuàng)建最少兩個(gè)數(shù)據(jù)庫(kù):一個(gè)索引數(shù)據(jù)庫(kù),一個(gè)或多個(gè)內(nèi)容數(shù)據(jù)庫(kù)。我把索引數(shù)據(jù)庫(kù)命名為YumDaysIndex,內(nèi)容數(shù)據(jù)庫(kù)命名為YumDaysNNN,其中的NNN是數(shù)字編號(hào),在剛開(kāi)始的時(shí)候,肯定只要一個(gè)YumDays001就夠了。
GRANT ALL PRIVILEGES ON YumDays001.* TO '********'@'%' IDENTIFIED BY '********' WITH GRANT OPTION;
CREATE DATABASE YumDaysIndex;
CREATE DATABASE YumDays001;
選擇YumDays001數(shù)據(jù)庫(kù),創(chuàng)建用戶(hù)表:
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、用戶(hù)名、密碼、昵稱(chēng)、密碼問(wèn)題、答案、email、QQ號(hào)、用戶(hù)角色、積分、相冊(cè)已經(jīng)使用的磁盤(pán)空間、注冊(cè)時(shí)間、登錄時(shí)間、是否刪除等。設(shè)計(jì)這個(gè)表的思路如下:
1、name只能用英文,因?yàn)樗鼘⑹荱RL的組成部分,為了便于用戶(hù)之間的識(shí)別,所以需要monicker(昵稱(chēng))字段;
2、根據(jù)用戶(hù)的score字段可以算出用戶(hù)的相冊(cè)容量,每次上傳圖片的時(shí)候,都增加albumusage字段的值,如果空間已經(jīng)被使用完,則不容許上傳;
3、ID使用UUID類(lèi)型,所以它的列類(lèi)型為char(32),之所以使用UUID,是因?yàn)閡sers表會(huì)被分割到很多個(gè)數(shù)據(jù)庫(kù)中,使用UUID可以保證ID的唯一性;
4、isdelete的列類(lèi)型也比較奇怪,為varchar(2),而默認(rèn)值卻是'0'(字符串),這是因?yàn)镾pringSide的實(shí)現(xiàn)中,在刪除數(shù)據(jù)的時(shí)候,會(huì)把這個(gè)字段設(shè)置為'-1'(字符串)。
從這個(gè)表中可以看出,這里涉及到一個(gè)用戶(hù)角色的問(wèn)題,不同的角色擁有不同的權(quán)限,所以需要一個(gè)Roles表。考慮到Roles表包含的記錄數(shù)不會(huì)太多,而且分布到多個(gè)服務(wù)器上也不好維護(hù),所以Roles表應(yīng)該放到索引服務(wù)器中。用戶(hù)登錄這樣的過(guò)程也應(yīng)該由索引服務(wù)器處理,然后將用戶(hù)的一些信息保存到Cookie中,不過(guò)如果用戶(hù)操作的時(shí)候需要查看權(quán)限,則一定要向索引服務(wù)器請(qǐng)求,索引服務(wù)器通過(guò)提供WebService來(lái)響應(yīng)請(qǐng)求,因?yàn)樵贑ookie中保存權(quán)限會(huì)出現(xiàn)安全問(wèn)題。
創(chuàng)建Roles表的代碼如下:
CREATE TABLE roles(
id char(32) NOT NULL PRIMARY KEY,
name varchar(20) NOT NULL,
privilegesflag varchar(255),
INDEX(name)
);
這里需要說(shuō)明的是privilegesflag字段,該字段我設(shè)計(jì)為一個(gè)用逗號(hào)隔開(kāi)的字符串,比如“post,reply”,代表用戶(hù)具有發(fā)帖、回帖的權(quán)限。這么設(shè)計(jì)的好處就是在開(kāi)發(fā)過(guò)程中,不用為了增加權(quán)限而修改數(shù)據(jù)表的結(jié)構(gòu),只用往這個(gè)表中加入新的字符串就行了,而Java代碼中,分割字符串又是那么的方便。
在這個(gè)表中,我初步設(shè)計(jì)的角色有四個(gè),它們分別是管理員、超級(jí)用戶(hù)、普通用戶(hù)和被鎖定用戶(hù)。當(dāng)然,如果網(wǎng)站規(guī)模越來(lái)越大,需要有人幫著把關(guān)時(shí)(否則肯定黃帖廣告貼泛濫),可能需要版主、編輯這樣的角色。
在我剛開(kāi)始設(shè)計(jì)這個(gè)系統(tǒng)時(shí),本來(lái)是加入了用戶(hù)群組的功能的,但是經(jīng)過(guò)這兩天的沉淀,我決定暫時(shí)還是不要這個(gè)功能了。以后再加上都可以,但是開(kāi)發(fā)初期我不想為自己找太多麻煩。
文章要進(jìn)行分類(lèi),因此需要?jiǎng)?chuàng)建一個(gè)分類(lèi)表,這個(gè)表依然保留在索引服務(wù)器上:
id char(32) NOT NULL PRIMARY KEY,
name varchar(20) NOT NULL,
INDEX(name)
);
這個(gè)表的內(nèi)容很簡(jiǎn)單,無(wú)需解釋。
再下面,就是用來(lái)保存文章的表了:
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)
);
該表應(yīng)該保存到內(nèi)容數(shù)據(jù)庫(kù)中。其中的字段都很好理解,從名字即可看出意義。其中需要解釋的兩個(gè)字段如下:
1、mainpicture:我希望每一篇文章都有一個(gè)主題圖片,該圖片在顯示文章列表的時(shí)候也可以顯示(當(dāng)然是縮略圖)。其內(nèi)容是一個(gè)URL。
2、accessmod:該字段保存了該文章的安全屬性,即是否公開(kāi)。取值為1則不公開(kāi),取值為3則完全公開(kāi)。那么2呢?那是我為用戶(hù)群保留的,取值為2則只正對(duì)該文章所屬的群公開(kāi)。
至于索引,那是要根據(jù)網(wǎng)站需要提供什么樣的功能來(lái)設(shè)計(jì)的。當(dāng)網(wǎng)站需要按照哪一個(gè)規(guī)則對(duì)文章進(jìn)行查找的時(shí)候,就要在該字段上建立索引,以便加快查找速度。
再往下,則是用來(lái)保存回復(fù)的表:
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
);
自己回復(fù)了哪些文章,心里也要有個(gè)數(shù),所以要建立一個(gè)表,用來(lái)記錄用戶(hù)參與了的文章:
id char(32) NOT NULL PRIMARY KEY,
userid char(32) NOT NULL,
topicid char(32) NOT NULL,
INDEX(userid)
);
再然后,是用來(lái)管理相冊(cè)和相片的表:
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是該相冊(cè)在服務(wù)器上的文件路徑,而miniphotopath則是縮略圖的路徑。accessmod也是起安全控制作用的,意義同前。
id char(32) NOT NULL PRIMARY KEY,
albumid char(32) NOT NULL,
filename varchar(20) NOT NULL,
INDEX(albumid)
);
這樣,內(nèi)容數(shù)據(jù)庫(kù)的表已經(jīng)差不多了,剩下的在開(kāi)發(fā)過(guò)程中再逐步完善。而索引服務(wù)器還只有前面提到的Roles表和Catalogs表,但是索引服務(wù)器要提供顯示首頁(yè)的功能,要提供反向代理的功能,要提供統(tǒng)計(jì)排序的功能。因此,我在索引數(shù)據(jù)庫(kù)中設(shè)計(jì)了以下表。
首先,索引服務(wù)器中也應(yīng)該保存有Users的所有數(shù)據(jù),需要保存所有的記錄,但是不需要保存所有的字段。初步的設(shè)計(jì)如下:
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)
);
這里保存有用戶(hù)的驗(yàn)證信息,因此簡(jiǎn)單的驗(yàn)證功能都可以通過(guò)索引服務(wù)器來(lái)完成。這里有兩個(gè)字段值得一提,一是score,用來(lái)保存用戶(hù)的分?jǐn)?shù),主要是為了實(shí)現(xiàn)用戶(hù)排名;另一個(gè)字段是webserver,它保存了該用戶(hù)會(huì)被分配到那個(gè)Web服務(wù)器。
索引服務(wù)器還應(yīng)該保存所有Topics的記錄,當(dāng)然,它不需要保存所有的字段,和Users表一樣,它只需要知道到哪個(gè)Web服務(wù)器可以找到這個(gè)Topic的所有數(shù)據(jù)就行了。初步設(shè)計(jì)如下:
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)
);
這個(gè)表非常簡(jiǎn)單,只是維護(hù)了一個(gè)所有Topic的索引而已,通過(guò)webserver字段就知道到哪里找它的詳細(xì)信息,索引服務(wù)器顯示主頁(yè)的時(shí)候,可以通過(guò)AJAX調(diào)用相應(yīng)的webserver來(lái)顯示它的摘要信息。time字段是用來(lái)排序的,catalog字段是用來(lái)分類(lèi)的。
我還有一個(gè)想法,就是想能夠按照最新的回復(fù)來(lái)對(duì)Topic進(jìn)行排序,基本上所有的論壇都是采取的這種方法,只需要有人回復(fù),文章就會(huì)被頂上去。但是,由于Topics是分布存儲(chǔ)的,所以需要有一個(gè)表用來(lái)保存最近被回復(fù)的文章的信息,而其它的服務(wù)器則可以通過(guò)定時(shí)服務(wù),每隔幾分鐘在自己的服務(wù)器上統(tǒng)計(jì)最新被回復(fù)的文章,然后提交到索引服務(wù)器。其結(jié)構(gòu)如下:
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)
);
這個(gè)表,只需要保存少量的紀(jì)錄就夠了。
還要一個(gè)統(tǒng)計(jì)表,維護(hù)一些統(tǒng)計(jì)信息,如注冊(cè)用戶(hù)數(shù)、文章總數(shù)、回復(fù)總數(shù)、響應(yīng)新用戶(hù)注冊(cè)的當(dāng)前服務(wù)器等等,如下:
usercount int NOT NULL,
topiccount int NOT NULL,
replycount int NOT NULL,
currentwebserver varchar(10) NOT NULL
);
這個(gè)表的名字是單數(shù)形式,因?yàn)檫@個(gè)表只需要一條紀(jì)錄就夠了。
索引服務(wù)器還需要維護(hù)所有的相冊(cè)信息,同Topics表一樣,其結(jié)構(gòu)如下:
id char(32) NOT NULL PRIMARY KEY,
time timestamp NOT NULL default CURRENT_TIMESTAMP,
webserver varchar(10) NOT NULL,
INDEX(time)
);
數(shù)據(jù)庫(kù)的設(shè)計(jì)到此告一段落,下一步就開(kāi)始寫(xiě)代碼了。數(shù)據(jù)庫(kù)設(shè)計(jì)中的缺陷,只有經(jīng)過(guò)實(shí)戰(zhàn)的檢驗(yàn)才能夠體現(xiàn)出來(lái)。