# 設計數據庫的規范
## 表名
- 全小寫
- 表前綴
確認是否自己要開發的系統里會引入別的系統的表,比方引入ucenter的表。
如果極大可能引入別的表,那么最好你的數據庫表名要帶表前綴`think_`。ucenter相關表可以為`uc_`。
- 長度
表名盡量用英文單詞將存儲的對象表示出來即可,比方`member`也可以用`user`來表示。雖然沒有上限,但是盡量簡潔。不用生僻的單詞來顯擺你的英文好。大道至簡,簡單的東西就不要搞的復雜,不要讓團隊成員有思考成本,表名不要用拼音,不要有歧義。
- 關鍵字
||||
|-|-|-|
|ADD |ALL |ALTER|
|ANALYZE|AND| AS|
|ASC |ASENSITIVE |BEFORE|
|BETWEEN |BIGINT |BINARY|
|BLOB |BOTH |BY|
|CALL |CASCADE |CASE|
|CHANGE |CHAR |CHARACTER|
|CHECK |COLLATE |COLUMN|
|CONDITION |CONNECTION |CONSTRAINT|
|CONTINUE |CONVERT |CREATE|
|CROSS |CURRENT_DATE |CURRENT_TIME|
|CURRENT_TIMESTAMP |CURRENT_USER |CURSOR|
|DATABASE |DATABASES |DAY_HOUR|
|DAY_MICROSECOND |DAY_MINUTE |DAY_SECOND|
|DEC |DECIMAL |DECLARE|
|DEFAULT |DELAYED |DELETE|
|DESC |DESCRIBE |DETERMINISTIC|
|DISTINCT |DISTINCTROW |DIV|
|DOUBLE |DROP |DUAL|
|EACH |ELSE |ELSEIF|
|ENCLOSED |ESCAPED |EXISTS|
|EXIT |EXPLAIN |FALSE|
|FETCH |FLOAT |FLOAT4|
|FLOAT8 |FOR |FORCE|
|FOREIGN |FROM |FULLTEXT|
|GOTO |GRANT |GROUP|
|HAVING |HIGH_PRIORITY |HOUR_MICROSECOND|
|HOUR_MINUTE |HOUR_SECOND |IF|
|IGNORE |IN |INDEX|
|INFILE |INNER |INOUT|
|INSENSITIVE |INSERT |INT|
|INT1 |INT2 |INT3|
|INT4 |INT8 |INTEGER|
|INTERVAL |INTO |IS|
|ITERATE |JOIN |KEY|
|KEYS |KILL |LABEL|
|LEADING |LEAVE |LEFT|
|LIKE |LIMIT |LINEAR|
|LINES |LOAD |LOCALTIME|
|LOCALTIMESTAMP |LOCK |LONG|
|LONGBLOB |LONGTEXT |LOOP|
|LOW_PRIORITY |MATCH |MEDIUMBLOB|
|MEDIUMINT |MEDIUMTEXT |MIDDLEINT|
|MINUTE_MICROSECOND |MINUTE_SECOND |MOD|
|MODIFIES |NATURAL |NOT|
|NO_WRITE_TO_BINLOG |NULL |NUMERIC|
|ON |OPTIMIZE |OPTION|
|OPTIONALLY |OR |ORDER|
|OUT |OUTER |OUTFILE|
|PRECISION |PRIMARY |PROCEDURE|
|PURGE |RAID0 |RANGE|
|READ |READS |REAL|
|REFERENCES |REGEXP |RELEASE|
|RENAME |REPEAT |REPLACE|
|REQUIRE |RESTRICT |RETURN|
|REVOKE |RIGHT |RLIKE|
|SCHEMA |SCHEMAS |SECOND_MICROSECOND|
|SELECT |SENSITIVE |SEPARATOR|
|SET |SHOW |SMALLINT|
|SPATIAL |SPECIFIC |SQL|
|SQLEXCEPTION |SQLSTATS |SQLWARNING|
|SQL_BIG_RESULT |SQL_CALC_FOUND_ROWS |SQL_SMALL_RESULT|
|SSL |STARTING |STRAIGHT_JOIN|
|TABLE |TERMINATED |THEN|
|TINYBLOB |TINYINT |TINYTEXT|
|TO |TRAILING |TRIGGER|
|TRUE |UNDO |UNION|
|UNIQUE |UNLOCK |UNSIGNED|
|UPDATE |USAGE |USE|
|USING |UTC_DATE |UTC_TIME|
|UTC_TIMESTAMP |VALUES |VARBINARY|
|VARCHAR |VARCHARACTER |VARYING|
|WHEN |WHERE |WHILE|
|WITH |WRITE |X509|
|XOR |YEAR_MONTH |ZEROFILL|
表名和字段名最好不要使用上面的保留字,如果使用 sql 語句里要 \`table\` 這樣的方式查詢才不會報錯。
## 字段名
字段名也是盡量表達意思完整的情況下用英語單詞,不要有歧義。如果是關聯表的主鍵字段要帶上關聯表名加下劃線,比方說article 表 和`article_content`表,`article_content` 表的關聯字段 應該為`article_id`
## 字段類型
主鍵 int 自增,unsigned
時間以前,我們為了方便經常是int,后來發覺經常數據庫去查看,int不友好,所以以后直接datetime。這樣phpmyadmin里顯示的就是實際日期時間。
一些短字符串類型盡量用varchar。然后默認值為空。手機號這種不要用int 用char(11)
有的業務類型用枚舉enum
序列化字段用varchar
長文本用text
## 默認值
varchar 默認值一般為空
datetime 最好勾上可為空
int 按實際需求,0 或者其他
enum 最好有個默認值
可以為空的類型 最好為空
我曾經和老大討論過數據庫默認值是依賴于程序插入還是數據庫,他說默認值最好在模型里寫死,不然會死的很慘。我當時也覺得靠數據庫這種,你不知道什么時候就會被別人修改,不提交到版本庫里的,始終不靠譜。
但是等我在極客優才用lazyphp做項目時,沒有數據層。只能靠數據庫。而且有很多測試環境,很多數據庫。我覺得在你只用mysql的情況下,靠sql保持一致性還是可行的。有的時候數據遷移只能靠sql,model無法生成形象直觀的表達,必須懂ThinkPHP的人才能看懂,并且當你寫錯的時候不運行,是不會報錯的。而sql,你用數據庫管理工具操作時int 默認值寫null,明顯會報出來。
## 備注comment
好的設計是能保存的,不要相信程序員的記憶,他們其實和魚一樣只有7秒的當初記憶。
寫好sql的文檔 這就是備注, 表備注,字段備注,修改了表結構記得更新備注啊。 一致性原則。
## 主鍵
最好所有表都有一個默認主鍵id, 別搞什么奇特的名字,如 表名_id 做主鍵等。
主鍵默認相當于一個索引。
TP對默認組合索引可能支持不是太好, model里有一個getPk方法
## 索引
如果你的表經常被檢索,建里索引是非常有效的加速方法。當然也有代價,插入會慢點。
所以 看看你的源碼 確認一個表內那些字段經常被搜索。一般的 id、name、title、status、type、cate_id 等是經常會被索引的。還有時間。
> 經常搜索的 字段 在建表時放前面。 這樣你在 phpMyadmin 里 有時數據少時你可以肉眼掃描出想要的數據。也方便自己搜索時選擇。

# freelog的數據庫設計
本著“大道至簡,開發由我”的原則,我盡量只建立能實現功能的表。沒有太多邏輯,比如用戶中心和ucenter打通之類的。
也沒有設計后臺用戶表,直接寫死在配置里,簡單實現登錄。
## fl_comment 評論表
| 字段 | 類型 | 注釋 |
|------------------|------------------|------------|
| id | int(11) unsigned | 主鍵 |
| post_id | int(11) unsigned | 日志id |
| content | text | 評論內容 |
| member_id | int(11) unsigned | 會員id |
| reply_comment_id | int(11) unsigned | 回復評論id |
| create_at | datetime | 創建時間 |
由于時間關系,我沒有實現一個評論功能,但是之前表有設計,一般來說 評論分兩種,一種是不嵌套的評論,該評論只屬于某篇文章,還一種來說就是有回復的評論。這時候就多了reply_comment_id字段。具體實現可以參考這篇 [《php無限級分類實現評論及回復》](http://www.tuicool.com/articles/aiEvArq)
只不過里面的parentid 就是我這里的reply_comment_id。
目前的實現是用的 “多說”社會化評論,這樣的好處是評論者不一定要注冊當前站點。
## fl_config 配置表
| 字段 | 類型 | 注釋 |
|-------------|----------------------|----------|
| id | int(10) unsigned | 配置ID |
| name | varchar(30) | 配置名稱 |
| type | tinyint(3) unsigned | 配置類型 |
| title | varchar(50) | 配置說明 |
| group | tinyint(3) unsigned | 配置分組 |
| extra | varchar(255) | 配置值 |
| remark | varchar(100) | 配置說明 |
| create_time | int(10) unsigned | 創建時間 |
| update_time | int(10) unsigned | 更新時間 |
| status | tinyint(4) | 狀態 |
| value | longtext | 配置值 |
| sort | smallint(3) unsigned | 排序 |
配置直接移植的OneThink的動態配置,可以實現配置的分組顯示和下面幾中類型

盡量不手動修改配置,這樣更靈活。
## fl_file 文件表
| 字段 | 類型 | 注釋 |
|-------------|---------------------|---------------|
| id | int(10) unsigned | 文件ID |
| name | char(30) | 原始文件名 |
| savename | char(20) | 保存名稱 |
| savepath | char(30) | 文件保存路徑 |
| path | varchar(255) | 全路徑 |
| ext | char(5) | 文件后綴 |
| mime | char(40) | 文件mime類型 |
| size | int(10) unsigned | 文件大小 |
| md5 | char(32) | 文件md5 |
| sha1 | char(40) | 文件 sha1編碼 |
| location | tinyint(3) unsigned | 文件保存位置 |
| url | varchar(255) | 遠程鏈接 |
| create_time | int(10) unsigned | 上傳時間 |
也是移植OneThink的file表。 不過后來為了統一上傳返回 加上了和picture表一樣的path字段。
## fl_picture 圖片表
| 字段 | 類型 | 注釋 |
|-------------|------------------|---------------|
| id | int(10) unsigned | 主鍵id自增 |
| path | varchar(255) | 路徑 |
| url | varchar(255) | 圖片鏈接 |
| md5 | char(32) | 文件md5 |
| sha1 | char(40) | 文件 sha1編碼 |
| status | tinyint(2) | 狀態 |
| create_time | int(10) unsigned | 創建時間 |
同樣移植于OneThink。 file 和picture 構成了本站的上傳文件存儲。
且可以支持多種上傳驅動。保存ftp、本地、sae等都可以。經過md5排重,減少冗余文件。
## fl_member 用戶表
| 字段 | 類型 | 注釋 |
|--------------|------------------|----------------------|
| id | int(11) unsigned | 主鍵 |
| email | varchar(320) | 郵箱 |
| email_status | tinyint(1) | 1 激活 0 未激活 |
| domain | varchar(32) | 域名 |
| nickname | varchar(64) | 昵稱 |
| sex | tinyint(1) | 性別 1-男 0-女 |
| birthday | date | 生日 |
| pwd | char(64) | 加密后的密碼 |
| settings | text | 配置序列化字段 |
| avatar | int(11) unsigned | 頭像圖片id |
| status | int(2) | -1 刪除 0禁用 1 有效 |
| create_at | datetime | 創建時間 |
| update_at | datetime | 更新時間 |
用戶表用于保存用戶注冊、登錄、更新個人資料的數據。其中domain是自定義域名,這個目前沒實現,avatar其實存的是裁剪過的圖片保存到圖片表里的id。
## fl_message 消息表
| 字段 | 類型 | 注釋 |
|----------------|---------------------|--------------------------------------|
| id | int(11) unsigned | 主鍵 |
| content | varchar(2048) | 消息 |
| member_id | int(11) unsigned | 所有者id |
| from_member_id | int(11) | 消息來源用戶 0 系統 大于0是member_id |
| is_read | tinyint(1) unsigned | 是否已讀 0 未讀 1 已讀 |
| create_at | datetime | 創建時間 |
消息表用于存站內信和私信。 一般站內信有兩種實現,一種是消息只存一條,不區分部分的已讀未讀。還一種是發的時候給所有用戶添加同一條站內信,這樣可以區分該用戶是否已讀。
`from_member_id` 是來源用戶id,如果是私信,就是發的人的`member_id` `member_id` 則是消息所有者也就是 接收的人。 如果是站內信 則 `from_member_id` 為0 member_id也為0。
## fl_post 文章表或日志表
| 字段 | 類型 | 注釋 |
|-------------|-------------------------------------------------|-----------------------------|
| id | int(11) unsigned | 主鍵 |
| title | varchar(256) | 標題 |
| description | text | 描述 |
| member_id | int(11) unsigned | 用戶id 0-為官方發布的 |
| type | enum('text','picture','music','video','single') | 日志類型 |
| deadline | datetime | 截止日期 用于定時發布 |
| tags | text | 標簽 |
| views | int(11) unsigned | 瀏覽數 |
| comments | int(11) unsigned | 評論數 |
| content | text | 內容 |
| status | int(1) | status -1刪除 0-草稿 1-正常 |
| create_at | datetime | 創建時間 |
| update_at | datetime | 更新時間 |
type 表名該文章的類型,預留了single單頁類型。用于存放“關于我"這種單頁的。
deadline 用于定時發布,查詢只查詢這個字段為真實發布時間,定時發布時存比當前時間吃的日期時間格式。
tags標簽字段 存標簽的內容‘,’分割。而標簽的統計在單獨的標簽表。
## fl_tags 標簽統計表
| 字段 | 類型 | 注釋 |
|-------------|------------------|------|
| id | int(10) unsigned | |
| title | varchar(200) | 標題 |
| description | varchar(200) | 描述 |
| count | int(10) unsigned | 數量 |
| order | int(10) unsigned | 排序 |
標簽統計表 當文章里插入標簽時如果該表沒有保存的標簽,就保存到該表,方便以后系統統計熱門標簽。seo、標簽云都可以。order可以以后自定義標簽顯示。
## fl_sns 第三方登錄表
| 字段 | 類型 | 注釋 |
|--------------|--------------|------------------------|
| id | int(11) | |
| member_id | int(11) | 用戶 |
| type | varchar(20) | 綁定平臺類型 |
| access_token | varchar(100) | |
| expires_in | varchar(10) | 授權失效時間 |
| name | varchar(100) | |
| openid | varchar(50) | |
| openkey | varchar(50) | |
| update_time | int(11) | 更新時間 |
| create_time | int(11) | 綁定時間,判斷是否過期 |
| status | tinyint(1) | 綁定狀態 |
| extend | text | 擴展字段 |
type 是第三方登錄類庫的驅動類型小寫。參考以前開發姐妹街時的第三方登錄設計。
## fl_url 外鏈表
| 字段 | 類型 | 注釋 |
|-------------|------------------|--------------|
| id | int(11) unsigned | 鏈接唯一標識 |
| url | char(255) | 鏈接地址 |
| short | char(100) | 短網址 |
| status | tinyint(2) | 狀態 |
| create_time | int(10) unsigned | 創建時間 |
參考OneThink,目前沒用到。但是可以作為短鏈優化用。也可以做下載站的鏈接處理用。
核心表就是post 和 tags以及member。
- 序
- 前言
- 內容簡介
- 目錄
- 基礎知識
- 起步
- 控制器
- 模型
- 模板
- 命名空間
- 進階知識
- 路由
- 配置
- 緩存
- 權限
- 擴展
- 國際化
- 安全
- 單元測試
- 拿來主義
- 調試方法
- 調試的步驟
- 調試工具
- 顯示trace信息
- 開啟調試和關閉調試的區別
- netbeans+xdebug
- Socketlog
- PHP常見錯誤
- 小黃鴨調試法,每個程序員都要知道的
- 應用場景
- 第三方登錄
- 圖片處理
- 博客
- SAE
- REST實踐
- Cli
- ajax分頁
- barcode條形碼
- excel
- 發郵件
- 漢字轉全拼和首字母,支持帶聲調
- 中文分詞
- 瀏覽器useragent解析
- freelog項目實戰
- 需求分析
- 數據庫設計
- 編碼實踐
- 前端實現
- rest接口
- 文章發布
- 文件上傳
- 視頻播放
- 音樂播放
- 圖片幻燈片展示
- 注冊和登錄
- 個人資料更新
- 第三方登錄的使用
- 后臺
- 微信的開發
- 首頁及個人主頁
- 列表
- 歸檔
- 搜索
- 分頁
- 總結經驗
- 自我提升
- 進行小項目的鍛煉
- 對現有輪子的重構和移植
- 寫技術博客
- 制作視頻教程
- 學習PHP的知識和新特性
- 和同行直接溝通、交流
- 學好英語,走向國際
- 如何參與
- 瀏覽官網和極思維還有看云
- 回答ThinkPHP新手的問題
- 嘗試發現ThinkPHP的bug,告訴官方人員或者push request
- 開發能提高效率的ThinkPHP工具
- 嘗試翻譯官方文檔
- 幫新手入門
- 創造基于ThinkPHP的產品,進行連帶推廣
- 展望未來
- OneThink
- ThinkPHP4
- 附錄