在将新功能推向生产环境时,最大的风险可能在于新代码所需的数据库修改。在Rails中,我相信他们有“迁移”,可以通过编程方式对开发主机进行更改,然后随着使用修订后模式的代码一起在生产环境中进行相同的更改。如果需要的话,还可以以同步的方式回滚两者。
是否有人遇到过类似的PHP / MySQL工具集?很想听听它,或任何程序化或流程解决方案,以帮助降低这种风险......
我不信任程序化迁移。如果仅仅是简单的更改,例如添加一个可空列,则直接将其添加到生产服务器上。如果更复杂或需要数据更改,则编写一对SQL迁移文件并针对副本数据库进行测试。
在使用迁移时,一定要测试回滚迁移。这是您的紧急“出问题了”按钮。
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...
我使用的解决方案(最初由我的一个朋友开发)是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
#!/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以进行更改,也可以为您进行更改。
@[yukondude]
我自己使用Perl,并且以类似Rails风格的迁移为例,半自动地进行了相同的操作。
我的做法是创建一个名为“version”的单个表,其中包含一个名为“version”的列,包含一个数字的单行,该数字是当前模式版本。然后编写一个脚本来读取该数字,在某个目录中查找并应用所有编号的迁移,以从这里到达那里(然后更新该数字),这样做相当容易。
在我的开发/阶段环境中,我经常(通过另一个脚本)将生产数据导入到暂存数据库中,并运行迁移脚本。如果您在上线之前这样做,您就可以相当确定迁移将起作用。显然,在暂存环境中进行广泛测试。
我在一个版本控制标记下标记新代码和所需的迁移。要部署到阶段或实时环境,您只需将所有内容更新到此标记并快速运行迁移脚本即可。(如果存在真正疯狂的模式更改,则可能需要安排短暂的停机时间。)
基本上就是Lot105所描述的。
每次迁移都需要有一个应用和回滚脚本,还有一种控制脚本,它会检查哪些迁移需要被应用并按适当的顺序应用它们。
然后每个开发人员都使用这个方案来保持他们的数据库同步,在应用到生产环境时,相关变更也会被应用。如果需要,可以使用回滚脚本撤销更改。
有些改变不能用像sqldiff这样的工具生成的简单ALTER脚本来完成;有些改变不需要模式更改而需要对现有数据进行编程更改。所以你无法进行概括,这就是为什么需要一个由人编辑的脚本。
我一直喜欢将我的开发站点指向与生产站点相同的数据库。这听起来可能有风险,但实际上它解决了许多问题。如果您在同一服务器上有两个站点指向相同的数据库,则可以实时准确地查看用户在上线时将看到什么。
您只需要一个数据库,只要您制定从不删除表中的列的策略,就知道您的新代码将与您正在使用的数据库匹配。
迁移时也会少很多麻烦。您只需要移动PHP脚本,它们已经使用相同的数据库进行了测试。
我还倾向于为任何目标用户上传的文件夹创建符号链接。这意味着没有混淆哪些用户文件已更新。
另一个副作用是将一小组“测试人员”移植到日常使用该网站的选项。这可能会导致大量反馈,您可以在公开发布之前实施。
这种方法可能并不适用于所有情况,但我已经开始将所有更新移动到这种模式。它使开发和发布更加顺畅。