# 设计数据库的规范
## 表名
- 全小写
- 表前缀
确认是否自己要开发的系统里会引入别的系统的表,比方引入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 里 有时数据少时你可以肉眼扫描出想要的数据。也方便自己搜索时选择。
![技巧](http://box.kancloud.cn/2015-06-06_557262d6a11e5.png)
# 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的动态配置,可以实现配置的分组显示和下面几中类型
![2015-06-06/5572fd68561b4](http://box.kancloud.cn/2015-06-06_5572fd68561b4.png)
尽量不手动修改配置,这样更灵活。
## 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
- 附录