本文是《Solo 从设计到实现》的一个章节,该系列文章将介绍 Solo 这款 Java 博客系统是如何从无到有的,希望大家能通过它对 Solo 从设计到实现有个直观地了解、能为想参与贡献的人介绍清楚项目,也希望能为给重复发明重新定义博客系统的人做个参考 ❤️

本章我们主要介绍 Solo 的表结构定义。一些公共约定:

  • 默认所有表都以 b3_solo_ 为表前缀
  • 对于日期时间类型,我们使用的是 UTC 毫秒时间戳,这样主要是为了避免引入时区问题。统一使用 bigint 存储 UTC 时间戳,程序里面处理时区转换
  • 没有外键约束
  • 没有关联查询,关联查询场景通过多次查询实现

可以说 Solo 是以“轻数据库重程序”的思路来主导设计和实现的。

关联表

关联表的表结构非常类似,用于记录一种数据和另一种数据的关联。

列名 类型 长度 备注
oId varchar 19 主键
type1_oId varchar 19 类型 1 的主键
type2_oId varchar 19 类型 2 的主键

在 Solo 中一共有 3 张关联表:

  • archivedate_article:存档 - 文章关联
  • category_tag:分类 - 标签关联
  • tag_article:标签 - 文章关联

其实理论上可以将这 3 张表合并为一张,通过加入一个“类型”列来区别关联类型,并预留一些各种类型的字段用于扩展。不过实际上我们并没有在 Solo 中这样做,因为表的数量并不重要,而且这样的抽象似乎意义不大。

当然,既然都这样想了,在 Solo 多年后的另一个博客系统中我们就真这样做了 😂 你有兴趣的话可以了解一下 Pipe

用户表 b3_solo_user

列名 类型 长度 备注
oId varchar 19 主键
userEmail varchar 255 用户邮箱
userName varchar 255 用户名
userURL varchar 255 用户链接地址
userPassword1 varchar 255 用户密码,MD5
userRole2 varchar 255 用户角色
userArticleCount3 int 11 用户文章计数
userPublishedArticleCount3 int 11 用户已发布文章计数
userAvatar varchar 255 用户头像图片地址
  • 1 用户密码使用 MD5 哈希后存储,这样并不是非常安全。正确的密码保存方式请参考《你保存用户密码的姿势正确吗?》
  • 2 用户角色的取值:
    • 管理员:adminRole
    • 普通用户:defaultRole
    • 访客用户:visitorRole
  • 3 所有文章(包括草稿)计数和已发布文章(不包括草稿)计数是在新建、删除文章时就进行计数,这样做是为了在查询列表分页数据时少一次 count,但这样做会限制查询条件,并且逻辑实现比较麻烦,所以后续版本可能会移除

文章表 b3_solo_article

列名 类型 长度 备注
oId varchar 19 主键
articleTitle varchar 255 文章标题
articleAbstract1 text 文章摘要
articleTags text 文章标签,英文逗号分隔
articleAuthorId varchar 19 文章作者 id
articleCommentCount int 11 文章评论计数
articleViewCount int 11 文章浏览计数
articleContent1 mediumtext 文章正文
articlePermalink varchar 255 文章访问路径
articleHadBeenPublished2 char 1 文章是否已经发布过
articleIsPublished2 char 1 文章是否处于发布状态
articlePutTop char 1 文章是否置顶
articleCreated bigint 20 文章创建时间戳
articleUpdated bigint 20 文章更新时间戳
articleRandomDouble3 double 文章随机数
articleSignId varchar 19 文章签名档 id
articleCommentable char 1 文章是否可评论
articleViewPwd4 varchar 100 文章浏览密码
articleEditorType varchar 20 文章编辑器类型5
  • 1 摘要和正文都是存的 markdown 原文,因为 md 也支持直接用 HTML,所以存 HTML 也是没有问题的,这主要看 markdown 渲染引擎的支持了
  • 2 对前端只提供了一个统一的更新接口,所以需要这两个字段来组合判断文章 / 草稿的操作是保存还是发布。这个方案不是一个好方案,好方案应该是只提供一个状态字段来记录文章的状态,并提供不同接口进行状态迁移
  • 3 文章随机数是用来实现随机文章的,MySQL 和 H2 虽然都提供了 RAND() 函数,但是性能实在太差。通过查询时指定一个随机数作为条件和该字段比较就可以非常简单高效地查询随机文章列表
  • 4 文章浏览密码如果留空表示不需要浏览密码,文章是公开可访问的
  • 5 编辑器类型用来保存该文章是用什么编辑器编辑的。Solo 在早些年提供了多款编辑器,后来砍掉了,统一使用内置的 CodeMirror-Markdown

评论表 b3_solo_comment

列名 类型 长度 备注
oId varchar 19 主键
commentContent text 评论内容
commentCreated bigint 20 评论创建时间戳
commentEmail varchar 255 评论人邮箱
commentName varchar 50 评论人名称
commentOnId varchar 19 评论文章或页面的 id
commentOnType varchar 20 评论文章或页面1
commentSharpURL varchar 255 评论访问路径,带 # 锚点
commentThumbnailURL varchar 255 评论人头像地址
commentURL varchar 255 评论人链接
commentOriginalCommentId2 varchar 19 父评论 id
commentOriginalCommentName varchar 50 父评论人名称
  • 1 评论文章或者自定义页面
    • 文章:article
    • 页面:page
  • 2 评论因为可以回复,所以是个树形结构。用关系型数据库表示即需要一个 parent id 来保存父子关系

导航 / 页面表 b3_solo_page

列名 类型 长度 备注
oId varchar 19 主键
pageCommentCount int 11 页面评论计数
pageContent mediumtext 页面内容
pageOrder int 页面导航栏排序
pagePermalink varchar 255 页面访问路径
pageTitle varchar 255 页面标题
pageCommentable char 1 页面是否可评论
pageType varchar 10 页面类型1
pageOpenTarget varchar 255 页面打开方式2
pageEditorType varchar 20 页面编辑器类型3
pageIcon varchar 255 页面小图标地址
  • 1 页面类型
    • 导航链接:link,出现在导航栏仅用于跳转
    • 普通页面:page,带标题和正文内容的页面
  • 2 打开方式指的是 a 标签里的 target 属性值
  • 3 和文章编辑器类型一样,目前内置 CodeMirror-Markdown

标签表 b3_solo_tag

列名 类型 长度 备注
oId varchar 19 主键
tagPublishedRefCount int 11 标签关联的已发布文章计数
tagReferenceCount int 11 标签关联的文章计数
tagTitle varchar 255 标签标题

分类表 b3_solo_category

列名 类型 长度 备注
oId varchar 19 主键
categoryTitle varchar 64 分类标题
categoryURI varchar 255 分类访问路径
categoryDescription text 分类描述
categoryOrder int 分类展现的排序
categoryTagCnt int 分类下聚合的标签计数

文章分类是通过聚合标签实现的:

  1. 将一组标签归类到一个分类下
  2. 用户发布文章时使用这组标签中的一个或多个
  3. 这篇文章将被自动聚合到该分类下
  4. 一篇文章可被归属于多个分类下

这样设计能让分类成为动态的,文章不用固定设置分类,可以随时通过调整分类包含的标签来达到动态聚合分类的效果。

存档日期表 b3_solo_archive

列名 类型 长度 备注
oId varchar 19 主键
archiveDateArticleCount int 11 存档日期文章计数,即某个月的文章总数
archiveDatePublishedArticleCount int 11 存档日期已发布的文章计数,即某个月的已发布文章总数
archiveTime bigint 20 存档日期时间,该月份第一天的时间戳

友链表 b3_solo_link

列名 类型 长度 备注
oId varchar 19 主键
linkAddress varchar 255 链接地址
linkDescription varchar 255 链接描述
linkOrder int 11 链接展现的排序
linkTitle varchar 255 链接标题

支持友链这个特性其实颇为画蛇添足,因为完全可以用自定义页面来实现友链页面。更进一步,自定义页面其实也是比较累赘的,其实只需要自定义导航,然后将这个导航跳转到某篇文章链接即可。这些过度设计在 Pipe 中得到了改进。

插件表 b3_solo_plugin

列名 类型 长度 备注
oId varchar 19 主键
author text1 插件作者
name varchar 255 插件名称
status varchar 10 插件状态2
version varchar 10 插件版本
setting text 插件数据,JSON3
  • 1 插件作者列值允许使用 HTML,所以这个字段用了 text 类型
  • 2 插件状态
    • 启用:ENABLED
    • 禁用:DISABLED
  • 3 插件相关的数据以 JSON 字符串形式保存

配置表 b3_solo_option

列名 类型 长度 备注
oId1 varchar 19 主键
optionValue text 配置项值
optionCategory varchar 20 配置项分类
  • 1 主键没有用时间戳,而是配置项键名,在 Option.java 中的 OPTION_ID_C_* 定义

表设计小节

Solo 的数据库设计我们一直在进行着修正和完善,相信最终我们会让它达到一个简约的状态,让大家能够一目了然的同时不影响功能和性能。

当然,这不仅仅是数据库设计的目标,在整个项目的技术方面,我们都会尽量朝着这个目标努力,好用并可读的程序才有可能成为一个受欢迎的项目,才有可能让更多的开源爱好者参与进来。


回到全文目录:《Solo 从设计到实现》

感谢    赞同    分享    收藏    关注    反对    举报    ...