推动新功能上线的最大风险可能在于新代码所需的数据库修改。在 Rails 中,我相信它们具有“迁移”功能,您可以在其中以编程方式对开发主机进行更改,然后将相同的更改与使用修改后的模式的代码一起进行。如果需要,以同步的方式回滚。
有没有人遇到过类似的 PHP/MySQL 工具集?很想听听它,或任何程序化或流程解决方案,以帮助降低风险......
我从来没有遇到过可以完成这项工作的工具。相反,我使用了单独的文件,编号以便我知道运行它们的顺序:本质上是 Rails 迁移的手动版本,但没有回滚。
这是我正在谈论的事情:
000-clean.sql # wipe out everything in the DB
001-schema.sql # create the initial DB objects
002-fk.sql # apply referential integrity (simple if kept separate)
003-reference-pop.sql # populate reference data
004-release-pop.sql # populate release data
005-add-new-table.sql # modification
006-rename-table.sql # another modification...
我从来没有真正遇到过这样做的任何问题,但它不是很优雅。跟踪给定更新需要运行哪些脚本取决于您(更智能的编号方案可能会有所帮助)。它也适用于源代码控制。
处理代理键值(来自自动编号列)可能会很痛苦,因为生产数据库可能具有与开发数据库不同的值。因此,如果可能的话,我尽量不要在我的任何修改脚本中引用文字代理键值。
我不相信程序化迁移。如果是简单的更改,例如添加一个 NULLable 列,我将直接将其添加到实时服务器。如果它更复杂或需要更改数据,我将编写一对 SQL 迁移文件并针对副本数据库对其进行测试。
使用迁移时,请始终测试回滚迁移。这是你的紧急“哦,狗屎”按钮。
我使用的解决方案(最初由我的一个朋友开发)是 yukondude 的另一个附录。
架构目录中的文件:
0-init.sql 1-add-name-to-user.sql 2-add-bio.sql
典型文件的外观,请注意每个 .sql 文件末尾的 db_schema 更新:
BEGIN;
-- comment about what this is doing
ALTER TABLE user ADD COLUMN bio text NULL;
UPDATE db_schema SET version = 2;
COMMIT;
“当前”脚本(用于 psql):
#!/bin/sh
VERSION=`psql -q -t <<EOF
\set ON_ERROR_STOP on
SELECT version FROM db_schema;
EOF
`
[ $? -eq 0 ] && {
echo $VERSION
exit 0
}
echo 0
更新脚本(也是 psql):
#!/bin/sh
CURRENT=`./current`
LATEST=`ls -vr *.sql |egrep -o "^[0-9]+" |head -n1`
echo current is $CURRENT
echo latest is $LATEST
[[ $CURRENT -gt $LATEST ]] && {
echo That seems to be a problem.
exit 1
}
[[ $CURRENT -eq $LATEST ]] && exit 0
#SCRIPT_SET="-q"
SCRIPT_SET=""
for (( I = $CURRENT + 1 ; I <= $LATEST ; I++ )); do
SCRIPT=`ls $I-*.sql |head -n1`
echo "Adding '$SCRIPT'"
SCRIPT_SET="$SCRIPT_SET $SCRIPT"
done
echo "Applying updates..."
echo $SCRIPT_SET
for S in $SCRIPT_SET ; do
psql -v ON_ERROR_STOP=TRUE -f $S || {
echo FAIL
exit 1
}
done
echo OK
我的 0-init.sql 具有完整的初始架构结构以及初始的“UPDATE db_schema SET version = 0;”。为 MySQL 修改这些脚本应该不会太难。就我而言,我也有
export PGDATABASE="dbname" export PGUSER="mike"
在我的 .bashrc 中。它会提示每个正在执行的文件的密码。
我以前用过这个工具,效果很好。
它将数据库连接或 SQL 文件作为输入,并将其与相同的(另一个数据库连接或另一个 SQL 文件)进行比较。它可以吐出 SQL 来进行更改或为您进行更改。
@[尤孔杜德]
我自己在使用 Perl,并且以同样的方式半手动地走上了 Rails 风格的迁移路线。
我所做的是有一个带有单列“版本”的表“版本”,其中包含一个数字的单行,这是当前架构版本。然后编写一个脚本来读取该数字,查看某个目录并应用所有编号的迁移以从那里到达这里(然后更新数字)是(非常)微不足道的。
在我的开发/阶段环境中,我经常(通过另一个脚本)将生产数据拉入暂存数据库,并运行迁移脚本。如果您在上线之前执行此操作,您将非常确定迁移将起作用。显然,您在暂存环境中进行了广泛的测试。
我在一个版本控制标签下标记了新代码和所需的迁移。要部署到舞台或现场,您只需将所有内容更新到此标签并相当快地运行迁移脚本。(如果架构更改真的很古怪,您可能希望安排短暂的停机时间。)
和 Lot105 描述的差不多。
每个迁移都需要一个应用和回滚脚本,并且您有某种控制脚本来检查需要应用哪些迁移并以适当的顺序应用它们。
然后每个开发人员使用此方案保持他们的数据库同步,并且在应用于生产时应用相关更改。如果有必要,可以保留回滚脚本以撤销更改。
某些更改无法使用简单的 ALTER 脚本完成,例如 sqldiff 之类的工具会产生;有些更改不需要架构更改,而是需要对现有数据进行编程更改。所以你不能真正概括,这就是为什么你需要一个人工编辑的脚本。
Symfony 有一个名为 sfMigrationsLight 的插件来处理基本的迁移。CakePHP 也有迁移。
无论出于何种原因,迁移支持从来都不是大多数 PHP 框架和 ORM 的高优先级。
我使用SQLyog复制结构,我总是,让我重复总是先备份。
过去我使用过LiquiBase,这是一个基于 Java 的工具,您可以在其中将迁移配置为 XML 文件。您可以使用它生成必要的 SQL。
今天我将使用Doctrine 2库,它具有类似于 Ruby的迁移工具。
Symfony 2框架也有一个很好的方式来处理模式的变化——它的命令行工具可以分析现有的模式并生成 SQL 来匹配数据库和改变的模式定义。
我一直更喜欢让我的开发站点指向与实时站点相同的数据库。乍一看,这听起来很冒险,但实际上它解决了许多问题。如果您在同一台服务器上有两个站点指向同一个数据库,则您可以实时准确地查看用户在它上线时将看到的内容。
您将永远只有 1 个数据库,只要您制定了从不从表中删除列的策略,您就知道您的新代码将与您正在使用的数据库匹配。
迁移时的破坏也明显减少。您只需要移动 PHP 脚本,它们已经使用相同的数据库进行了测试。
我还倾向于为作为用户上传目标的任何文件夹创建符号链接。这意味着不会混淆哪些用户文件已被更新。
另一个副作用是可以选择移植一小群“beta 测试人员”以在日常使用中使用该站点。这可能会带来很多反馈,您可以在公开发布之前实施这些反馈。
这可能不适用于所有情况,但我已开始将所有更新移至此模型。它使开发和发布更加顺利。