ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

CMS前后台源码拆解、二次开发与上线排错指南

CMS前后台源码拆解、二次开发与上线排错指南

简介:这份下载包围绕免费开源的CMS内容管理系统展开,面向希望搭建网站、学习内容管理流程或进行二次开发的站长、初学者与Java Web开发者,提供前后台代码及相关工程材料,可用于理解内容发布、用户管理、权限控制与前台展示等模块的实现思路。压缩包以zip格式分发,大小约13.38MB,文件总数暂显示为0,文件类型明细暂无数据;解压后需以实际目录为准,结合描述可预期其中涉及前后台代码、数据库文件与配置说明等,便于按模块查阅。已有244人学习或下载,说明该CMS主题具备一定关注度。结合描述,读者可重点了解开源许可下的使用边界、基于Java技术栈的CMS性能与扩展性考量,以及database目录所体现的内容存储与查询设计,为二次开发、功能定制和网站维护提供参考。

1. 一套 CMS 前后台代码,怎么拆才能当天跑起来

上周一个做外包的同行接了个活:客户要企业官网,带新闻栏目、产品展示和留言板,五天交付。他没从零写,而是找了一套 CMS 免费开源的网站前后台代码,换模板、配栏目、加两个字段就交了。这类源码包的价值不在“学习”,在于它已经跑通了内容录入、栏目管理、模板渲染、角色权限这几条主线,你只需要把业务塞进去。它适合三类人:赶周期的外包与小团队、要交课程设计但不想只写增删改查的同学、以及手里有多个站点想复用同一套后台的开发者。下面按我实际拆包的顺序走一遍:代码怎么分层、环境怎么搭、哪里能动手、哪里最容易翻车。

2. 拆骨架:前后台代码的分层与一次请求的完整链路

拿到源码包,第一件事不是打开首页看效果,而是先看清楚目录怎么分。分不清哪块是框架、哪块是业务、哪块是配置,后面每改一个地方都要靠猜,这种猜出来的经验没有复用价值。这一章把结构摊开,后面三章才好动刀。

2.1 前台、后台、公共层:三块代码各管什么

成熟一点的 CMS 源码,根目录基本是同一套思路:app放业务、public做 Web 根、config放配置、template放视图、runtime放缓存和日志。前台和后台共用同一个入口文件,靠 URL 里的模块名区分,这样公共的模型层、数据库连接、权限校验只写一份。

# 典型的 CMS 源码根目录结构,前后台共用一套入口 cms-root/ ├── app/ # 业务代码,按模块切分 │ ├── admin/ # 后台:控制器、表单定义、菜单配置 │ ├── home/ # 前台:控制器与页面逻辑 │ ├── api/ # 接口层,给 H5 / 小程序复用同一套模型 │ └── common/ # 公共模型、助手函数、权限校验 ├── public/ # Web 根目录,站点只暴露这一层 │ ├── index.php # 唯一入口文件 │ ├── static/ # css / js / 图片,可走 CDN │ └── uploads/ # 上传落盘位置,需要写权限 ├── config/ # 数据库、站点域名、缓存、邮件配置 ├── template/ # 前台模板,按主题分目录 ├── runtime/ # 编译缓存、日志,需要写权限 └── extend/ # 第三方 SDK 与自定义扩展

看这份结构要注意三件事。第一,public之外的东西都不应该被浏览器直接访问,如果你的 Nginx 根目录指到了项目根而不是public,配置文件、.sql安装包、日志全都能被下载,这是最常见的部署事故。第二,runtime和public/uploads是唯二需要写权限的目录,其余目录保持只读,出问题时先怀疑这两个目录的属主。第三,extend是给你自己加东西的地方,尽量别直接改common里的公共函数,升级或换版本时那部分会被覆盖。

判断一套代码值不值得投入时间,我一般看两点:app/common里有没有把权限和数据库连接抽出来,template里有没有做公共片段的 include。这两点决定你后面是改三处还是改三十处。

2.2 从 URL 到页面:一次文章详情请求经过的六个环节

把首页打开只是开始,真正要理解的是“一次请求怎么走到模板”。以访问/news/42.html这种伪静态地址为例,链路大致是六步,每步出问题的表现都不一样,记下这张表,排查时能省很多时间。

环节做的事出问题时的典型表现
入口文件定义路径常量、加载配置与自动加载全站白屏,日志里是 require 失败
路由解析把 PATH_INFO 拆成模块/控制器/方法除首页全 404,或跳到了错误模块
权限与参数校验校验登录态、节点权限、参数白名单后台能进但点菜单 403
控制器取参数、调模型、组装数据页面骨架在但数据区为空
模型与缓存查库、读缓存、拼装关联数据数据改了前台不更新
模板渲染变量注入、编译模板、输出页面报变量未定义,或样式全丢

入口文件通常长这样,代码不多但决定了整个分发逻辑:

<?php // public/index.php —— 所有前台/后台请求的唯一入口 define('APP_PATH', dirname(__DIR__) . '/app/'); // 1. 加载基础配置、自动加载器和路由表 require dirname(__DIR__) . '/config/bootstrap.php'; // 2. 从 PATH_INFO 解析模块/控制器/方法,缺省落到 home 模块首页 $path = trim($_SERVER['PATH_INFO'] ?? 'home/index/index', '/'); [$module, $controller, $action] = array_pad(explode('/', $path), 3, 'index'); // 3. 模块白名单,防止通过 ../ 拼出越权路径 if (!in_array($module, ['home', 'admin', 'api'], true)) { http_response_code(404); exit('module not found'); } // 4. 交给对应模块的控制器,视图在控制器内部渲染 require APP_PATH . "{$module}/controller/{$controller}.php";

这段代码里有三个参数值得盯:PATH_INFO依赖服务器把路径透传过来,Nginx 下要配fastcgi_param PATH_INFO,否则永远走缺省值;模块白名单是必要的,任何从 URL 拼出来的文件路径都必须过白名单;控制器名直接拼进require有风险,正规写法是先转成首字母大写再补.php,并对$controller做同样的白名单或文件存在性判断。我见过一个包这里直接用原始参数拼路径,改两行就能读到系统文件,属于拿到就得先修的地方。

2.3 四张核心表决定了这套 CMS 能走多远

CMS 的表看着多,核心其实就四张:栏目、内容、用户、附件。其余的表(权限节点、配置项、操作日志)都是围着这四张转。理解它们的字段设计,比读控制器代码更能判断这套系统的上限。

表关键字段设计要点
栏目表id、parent_id、path、sort、templatepath存物化路径如/news/tech/,查子树不用递归
内容表id、category_id、title、content、status、published_at、deleted_atstatus建议用整数枚举,软删除比物理删除好回滚
用户表id、username、password、role_id、last_login_at密码必须走哈希,last_login_at方便查异常登录
附件表id、path、mime、size、uploader_id、used_count记录引用计数,删除内容时才知道图能不能清

栏目表最容易做错的地方是树结构。用parent_id单字段存父子关系,取“某栏目及其所有子栏目下的文章”就得递归查库,栏目一多就是明显的慢查询。带path物化路径的包会好很多,一条 SQL 就能覆盖子树:

-- 取某栏目及其子栏目下最新的 10 篇已发布文章 SELECT a.id, a.title, a.url_path, a.published_at FROM cms_article a JOIN cms_category c ON c.id = a.category_id WHERE c.path LIKE '/news/%' -- 物化路径前缀匹配,避免递归查树 AND a.status = 1 -- 1 = 已发布,具体取值以包里的枚举定义为准 AND a.deleted_at IS NULL ORDER BY a.published_at DESC LIMIT 10;

参数说明:path LIKE '/news/%'里的前导斜杠不能省,否则会把/news-old/也匹配进来;status的枚举值各包不一样,动代码前先把注释或字典表看一遍,别按经验硬套;加deleted_at IS NULL是因为软删除的文章还在表里,漏掉这条前台就会出现“删了还在”的玄学现象。如果包里栏目表只有parent_id没有path,也不用慌,加一列path再写个脚本刷一遍数据就行,属于低成本的改良。

3. 把源码跑起来:环境对齐、配置改写与后台首次登录

源码包跑不起来,八成不是代码问题,是环境和权限没对齐。这一章按“先检查、再改配置、后导数据、最后验证”的顺序走,每一步都有明确的成功标志,卡住了能立刻定位到哪一环。

3.1 版本对齐:环境清单里最容易忽略的三项

动手前先把下面这张表逐项对一遍,尤其是后两项,很多“跑不起来”都是它们引起的。

组件建议取值检查命令容易忽略的点
PHP7.4 以上,优先 8.0/8.1php -v包里用了已废弃的函数会在 8.x 直接报错
扩展pdo_mysql、mbstring、gd、fileinfo、opensslphp -m缺 gd 上传图片不生成缩略图,缺 fileinfo 判断不了 MIME
数据库MySQL 5.7 / 8.0 或同版本分支mysql --version8.0 默认排序规则变了,老 SQL 可能报错
Web 服务器Nginx 或 Apachenginx -v根目录必须指到public
依赖工具Composer、Node(若前端用构建)composer -V缺 vendor 目录时页面直接白屏
# 一次性把关键项打出来,贴到记事本里备查 php -v php -m | grep -E 'pdo_mysql|mbstring|gd|fileinfo|openssl' # 缺哪个装哪个 mysql --version nginx -v composer -V

上面这几行输出的重点不是“有没有装”,而是“版本组合对不对”。pdo_mysql缺失时页面通常只报一句数据库连接失败,看不出根因;gd缺失时上传正常但缩略图 404,很容易误判成权限问题。composer install之前先看一眼包里的composer.json,如果锁文件里的依赖要求 PHP 8.1 而你本地是 7.4,别降级依赖,直接换 PHP 版本更快。

3.2 配置文件里必须改掉的五个值

配置文件一般只有一个,改完这一处基本就能连上库。下面这段是常见形态,字段名各家不同,但需要改的五项是一样的:

<?php // config/database.php —— 只动这五项,其余保持默认 return [ 'host' => '127.0.0.1', // 别写 localhost,走 socket 时行为可能和 TCP 不一致 'port' => 3306, 'dbname' => 'cms_demo', 'username' => 'cms_user', // 不要用 root,后面迁生产会锁死自己 'password' => 'ChangeMe_2024', 'charset' => 'utf8mb4', // utf8 存不了 emoji 和部分生僻字,务必 utf8mb4 'prefix' => 'cms_', // 表前缀,多站点共库时靠它隔离 ];

host写127.0.0.1而不是localhost,是因为部分环境下localhost会走 unix socket,而你在数据库里建的账号是'cms_user'@'127.0.0.1',两边对不上就报拒绝访问;charset必须是utf8mb4,用utf8时后台录入的 emoji 会被静默截断,等发现时数据已经缺了一块;prefix决定了安装 SQL 能不能直接导入,如果导入脚本里写死了表名,要么改配置要么改 SQL,两边必须一致。

还有一类配置不在这个文件里,但同样必须改:站点域名、上传目录、缓存驱动、调试开关。调试开关在本地要打开(否则报错只有白屏,等于黑匣子),上线前必须关掉,这个开关忘了关导致堆栈信息暴露的案例,我每年都能碰到几次。

3.3 建库、导数据与后台账号初始化

环境对了,接下来是建库和导入。这一步的血泪经验是:建库时就显式指定字符集,别指望服务器默认值,默认值在不同机器上真的不一样。

# 1. 建库,字符集和排序规则一起指定,避免继承服务器的 latin1 默认值 mysql -uroot -p -e "CREATE DATABASE cms_demo DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" # 2. 建业务账号,只授权这一个库,最小权限 mysql -uroot -p -e "CREATE USER 'cms_user'@'127.0.0.1' IDENTIFIED BY 'ChangeMe_2024'; GRANT ALL PRIVILEGES ON cms_demo.* TO 'cms_user'@'127.0.0.1'; FLUSH PRIVILEGES;" # 3. 导入安装 SQL,显式指定字符集,否则中文注释和默认数据会变问号 mysql -ucms_user -p --default-character-set=utf8mb4 cms_demo < install/cms_demo.sql # 4. 运行时目录和上传目录给写权限,属主必须是 php-fpm 的运行用户 chown -R www-data:www-data runtime public/uploads chmod -R 755 runtime public/uploads

四步里第三步最容易被跳过参数。--default-character-set=utf8mb4不加,在某些终端下导入的中文会变成???,而且不报错,等你打开后台看到一堆问号时,往往已经把安装 SQL 删了。第四步的www-data要换成你机器上 php-fpm 实际跑的账户,用ps aux | grep php-fpm看一眼就有答案,写错属主和没给权限是同一个结果:上传失败、缓存写不进去、日志不落盘。

导入完成后访问后台登录地址,用安装 SQL 里的默认账号登录,进去第一件事是改密码,第二件事是新建一个管理员账号自己用,把默认号停掉。

3.4 起来之后先做三项连通性验证

页面能打开不等于部署成功,我一般按三项验证,全过了才算跑通:

第一项,前台首页返回 200 且静态资源加载正常,打开浏览器控制台看有没有 404 的 css/js,有的话检查public/static的路径配置和 Nginx 的静态资源放行规则。第二项,后台登录后发一篇测试文章并设置成已发布,回前台看能不能访问到详情页,这一步同时验证了写库、缓存刷新和伪静态。第三项,上传一张图,确认文件落到了public/uploads且前台能显示。

Nginx 的站点配置建议直接按下面这段起步,重点在root和try_files两行:

server { listen 80; server_name cms.local; root /data/www/cms/public; # 必须指到 public,指到项目根会暴露配置和 SQL index index.php; location / { try_files $uri $uri/ /index.php$is_args$args; # 伪静态总入口,缺这行除首页全 404 } location ~ \.php$ { fastcgi_pass unix:/run/php/php-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~* \.(jpg|png|gif|css|js)$ { expires 7d; # 静态资源直接放行,别转给 PHP 处理 } }

root指错是新手最常见的一步,指到项目根目录时首页可能也能开,但config和install目录同时暴露在公网,属于必须在上线前掐掉的隐患。try_files的作用是把所有不存在的路径交给index.php,由框架内部再去解析,缺了它,详情页、列表页、后台路由全部 404,只剩首页能进。

4. 二次开发动刀点:模板、字段、路由、权限四处改法

跑通之后才是真正的工作:把别人的站改成客户的站。改动集中在四个地方——模板、字段、路由菜单、权限,这四处基本覆盖了八成以上的定制需求,改法也有固定套路,按套路走比每次现翻代码快得多。

4.1 改前台页面:模板变量从哪来、公共片段怎么抽

改前台的第一步不是打开 HTML 就开始删,而是先搞清楚“这个变量是谁传进来的”。控制器的assign或fetch调用决定了模板里能拿到什么,模板里出现未定义变量,先回头找控制器,别在模板里乱加判断。

<!-- template/home/detail.html —— 文章详情页 --> {include file="home/header.html"} <!-- 公共头,导航只维护一处 --> <article class="post"> <h1>{$article.title|htmlspecialchars}</h1> <!-- 纯文本输出一律转义 --> <div class="meta"> {$article.category.name} · {$article.published_at|date="Y-m-d"} </div> <div class="body">{$article.content}</div> <!-- 富文本,依赖入库前已过滤 --> </article> {include file="home/footer.html"}

这段模板里有两点是硬规矩。{$article.title}后面挂htmlspecialchars,是防止文章标题里带尖括号把页面结构冲掉;{$article.content}不加转义,因为它本身就是 HTML,但前提是入库时做过白名单过滤,这条在第 5 章会单独讲。公共头尾用include而不是复制粘贴,看起来是小事,等客户说“导航要加一个栏目”时就知道差别了——改一处还是改二十处。

换模板的顺序建议是:先复制一套原模板到新目录,改配置指向新目录,再在新目录上动刀。直接在默认模板上改,出问题没有对照版本,回滚都找不到基准。

4.2 加一个业务字段:从建表到前台输出的三步

客户提的“加个来源作者”,本质是三步:加列、加表单、加输出。三步缺一步就表现为“后台填了前台不显示”或者“前台有位置后台没入口”。

-- 第一步:文章表加一列,放在 title 后面方便肉眼核对 ALTER TABLE cms_article ADD COLUMN source_author VARCHAR(64) NOT NULL DEFAULT '' COMMENT '原文作者' AFTER title, ADD INDEX idx_source_author (source_author);
<?php // 第二步:app/admin/form/ArticleForm.php —— 后台表单字段声明 // 字段名必须和表列名完全一致,否则保存时会被过滤掉 return [ 'title' => ['type' => 'text', 'label' => '标题', 'required' => true, 'max' => 120], 'source_author' => ['type' => 'text', 'label' => '来源作者', 'required' => false, 'max' => 64], 'category_id' => ['type' => 'select', 'label' => '所属栏目', 'required' => true, 'source' => 'category_tree'], 'content' => ['type' => 'editor', 'label' => '正文', 'required' => true], 'status' => ['type' => 'radio', 'label' => '状态', 'options' => [0 => '草稿', 1 => '已发布']], ];

表单配置里type决定了渲染成什么控件,required决定是否必填校验,max一般同时作用于前端长度提示和服务端截断,两处都要生效。加完字段别急着看前台,先去后台保存一条数据,再直接查库确认列里有值——顺序反了的话,前台不显示时你分不清是表单没存进去还是模板没输出。

第三步是输出,详情页和列表页都要加{$article.source_author}。列表页容易漏,因为列表通常只查了少数字段,如果模型的field白名单里没有新列,模板上写了也是空的,这时候要回去改查询字段列表。

4.3 新增一个后台模块:菜单、路由、控制器三处对齐

加一个“订单管理”这种新模块,改动点固定是三处,少一处就点不进去或者点进去空白。第一处是菜单配置,第二处是控制器目录,第三处是权限节点。

<?php // app/admin/config/menu.php —— 后台左侧菜单,node 要和权限节点表对上 return [ ['title' => '内容管理', 'children' => [ ['title' => '文章列表', 'url' => 'admin/article/index', 'node' => 'article:list'], ['title' => '栏目管理', 'url' => 'admin/category/index', 'node' => 'category:list'], ]], ['title' => '订单管理', 'children' => [ // 新增模块只在这一层追加 ['title' => '订单列表', 'url' => 'admin/order/index', 'node' => 'order:list'], ]], ];

菜单里的url要和路由解析规则对应,node要和权限表里的节点名对应,两处写错的表现不同:url写错是点进去 404,node写错是菜单看得见但点开 403。控制器建在app/admin/controller/Order.php,类名与文件名大小写一致,方法名对应菜单里的动作。做完这三处,清一次runtime里的编译缓存再刷新,否则新菜单可能不出现——这个坑在第 5 章还会再提一次。

4.4 权限做到按钮级:节点表与校验函数

很多包的权限只做到菜单级,能看到菜单就能操作,这在多人后台里迟早出事。按钮级权限的做法是:每个操作对应一个节点名,控制器方法入口调一次校验函数,前端按同一份节点列表决定按钮显不显示。

<?php // app/common/auth.php —— 按钮级校验,控制器方法第一行调用 function check_node(string $node): void { $user = $_SESSION['admin_user'] ?? null; if (!$user) { // 未登录直接踢回登录页 header('Location: /admin/login'); exit; } // 超级管理员放行,其他人查会话里的节点列表;节点名写死在代码里,不信任前端传参 if ((int)$user['role_id'] === 1) { return; } if (!in_array($node, $user['nodes'] ?? [], true)) { http_response_code(403); exit('无权限:' . htmlspecialchars($node)); } } // 控制器里的用法:check_node('order:delete');

这段的关键是“节点名写死在服务端代码里”。前端隐藏按钮只是体验优化,用户直接构造请求照样能打到接口,服务端不校验等于没做权限。role_id === 1的超级管理员判断建议保留,但上线后要确保这个角色只有一两个账号,别为了省事给所有人开超管。

5. 上线前必踩的五个坑:从 404 到中文乱码的排查记录

下面五条是我在不同项目里反复遇到的,每条都按“现象、原因、解决”写,遇到时对号入座就行,不用重新推理一遍。

5.1 除首页外全部 404:伪静态没生效

现象:首页能打开,点任何栏目、文章、后台菜单都是 404,URL 里能看到.html或者带斜杠的路径。

原因:Web 服务器没把不存在的路径转给入口文件,请求直接落到了文件系统上找不到对应文件。另一种情况是配置写了但没重载,Nginx 还在跑旧配置。

解决:确认站点配置里有try_files $uri $uri/ /index.php$is_args$args;,Apache 环境下确认.htaccess被AllowOverride放行、mod_rewrite已启用。改完执行nginx -t检查语法,再nginx -s reload。如果用了 CDN 或反向代理,还要确认它没有把带参数的请求拦掉。

5.2 图片上传成功但前台裂图:目录属主和路径双重问题

现象:后台提示上传成功,列表里也有文件名,但前台图片是破图标,直接访问图片地址返回 403 或 500。

原因:文件确实落盘了,但落盘目录的属主不是 php-fpm 的运行用户,或者目录权限是 700 导致 Web 服务器读不到;还有一种情况是配置里的上传域名还写着本地地址,前台拼出来的 URL 指向了错误主机。

解决:ls -l public/uploads看属主,不对就chown -R改成 php-fpm 用户;权限给 755,文件 644。再检查配置里的上传域名和协议(http/https 混用会触发浏览器拦截)。最后确认open_basedir没把上传目录排除在外,这个限制触发时报错信息很含糊,容易误判。

5.3 改了模板前台毫无变化:三层缓存叠在一起

现象:模板文件明明改了,刷新前台还是老样子,清浏览器缓存、换浏览器、开无痕都没用。

原因:缓存叠了三层。模板引擎自己有一层编译缓存(runtime下的编译文件),PHP 有 OPcache,如果前面还挂了 CDN 或 Nginx 的proxy_cache,那就是三层以上。只清浏览器缓存当然没用。

解决:按顺序清——先删runtime下对应模块的编译目录,再systemctl reload php-fpm让 OPcache 失效,最后刷 CDN 缓存。日常开发时把模板编译的“强制重新编译”开关打开,能省掉大量重复操作;上线后关掉,靠手动清理。

5.4 后台富文本把脚本带进前台:入库前必须过滤

现象:后台编辑器里粘贴的内容在前台渲染后页面错乱,或者莫名其妙弹出提示框,严重时后台 Cookie 被读走。

原因:富文本内容以 HTML 入库,前台直接原样输出,中间没有任何过滤。编辑器前端能做一点限制,但请求是可以手工构造的,前端过滤等于没有。

解决:入库前做白名单过滤,只保留p、br、strong、img、a这类标签,属性上只留src、href、alt、title,href和src还要校验协议不是javascript:。前台输出富文本时不转义但必须信任过滤结果,非富文本字段一律转义。这两条是配套的,只做一半等于没做。

5.5 搬家后中文变问号:字符集与排序规则不一致

现象:本地一切正常,迁到服务器后后台文章标题、栏目名里的中文全变成???或者乱码方块。

原因:新库建的时候用了服务器默认字符集(常见是 latin1),或者导入时没指定字符集,连接层、表、字段三处的字符集不一致。

解决:先查SHOW VARIABLES LIKE 'character_set%'和SHOW CREATE TABLE cms_article,看连接、库、表、列四层是不是都是utf8mb4。不一致就把库和表改过来,重新用--default-character-set=utf8mb4导入一次原始 SQL,再核对数据。已经写坏的数据没法自动还原,只能从备份重来,所以迁移前先做一次全量备份,这份后悔药很便宜。

6. 从能跑到敢改:改动留痕与上线前十分钟自检

能跑起来只是及格线,敢在上面持续改才是这套源码真正的价值。我现在的习惯是:任何改动都先建一个分支或复制一份目录,改完在文件头部留一行注释写明日期和改动点,模板改动单独记一份清单。听起来土,但换版本或者排查“上周还好好的这周坏了”时,这份清单能省下大半天。

上线前的十分钟自检,我固定跑这张表:

检查项判断标准不通过时先看哪
站点根目录只指向publicNginxroot配置
调试开关已关闭配置文件里的 debug 项
目录权限runtime、uploads可写,其余只读属主与open_basedir
伪静态详情页、列表页、后台路由均可访问try_files
上传链路图片能传、能显示、能删除目录权限与上传域名
默认账号默认管理员已改密或停用用户表
数据备份有一次可用的全量导出备份文件大小与导入测试

表格里最容易被跳过的是最后一行。备份不是导出了就算,要实际导入到一个测试库里验证能还原,否则真出事时才发现备份是半截文件。另一条经验是:改数据库结构之前先导出该表,改模板之前先复制一份原文件,成本几乎为零。

如果只让我留一个技巧,那就是给每次改动打一个可回滚的标记。拿文章表加字段来说,我会把ALTER语句、回滚语句、受影响的文件和模板路径写进同一个改动记录里:

-- 改动记录:2024-xx-xx 文章表新增来源作者 ALTER TABLE cms_article ADD COLUMN source_author VARCHAR(64) NOT NULL DEFAULT '' AFTER title; -- 回滚语句(保留到确认稳定后再删) -- ALTER TABLE cms_article DROP COLUMN source_author;

这份记录的价值不在写的时候,在两个月后有人问“这个字段哪来的、能不能删”的时候。我从一次把线上栏目表结构改坏、又没有回滚语句、只能从三天前的备份恢复的经历之后,每次动表结构都强制先写回滚语句再执行正向语句,顺序反了就不许自己敲回车。希望这些能帮到你少走两段弯路。

本文还有配套的精品资源,点击获取

返回列表