将数据库更改从开发迁移到实时
启用新功能的最大风险可能在于新代码所需的数据库修改。在Rails中,我相信它们具有"迁移"功能,我们可以在其中以编程方式对开发主机进行更改,然后与使用修订后的模式的代码一起进行相同的更改。并在需要时以同步方式将它们回滚。
有没有人遇到过类似的PHP / MySQL工具集?很想听听它,或者有任何编程或者过程解决方案来帮助降低这种风险...
解决方案
回答
Symfony有一个名为sfMigrationsLight的插件,可以处理基本迁移。 CakePHP也有迁移。
无论出于何种原因,迁移支持对于大多数PHP框架和ORM从来都不是真正的优先事项。
回答
我从来没有遇到过可以完成这项工作的工具。取而代之的是,我使用了单独的文件(编号),以便我知道运行它们的顺序:本质上是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迁移文件,并针对副本数据库进行测试。
使用迁移时,请始终测试回滚迁移。这是紧急"哦该死"按钮。
回答
我使用SQLyog复制结构,并且我总是,让我重复一遍,总是先做一个备份。
回答
我以前使用过该工具,并且效果很好。
http://www.mysqldiff.org/
它以一个数据库连接或者一个SQL文件作为输入,并将其与相同的文件(另一个数据库连接或者另一个SQL文件)进行比较。它可以吐出SQL来进行更改或者为我们进行更改。
回答
@ [yukondude]
我自己在使用Perl,并且以相同的方式半手动地沿Rails式迁移的路线走了。
我所做的是只有一个表"版本"和一个列"版本",其中包含一个数字为当前模式版本的单行。然后,编写一个脚本来读取该数字,在某个目录中查找并应用所有编号的迁移从那里到此处(然后更新该数字),这是(非常)琐碎的。
在我的开发/阶段环境中,我经常(通过另一个脚本)将生产数据拉入登台数据库,并运行迁移脚本。如果我们在上线之前进行了此操作,那么我们将确定迁移将正常进行。显然,我们在登台环境中进行了广泛的测试。
我在一个版本控制标签下标记了新代码和所需的迁移。要部署到舞台或者现场,我们只需将所有内容更新到该标签并相当快地运行迁移脚本即可。 (如果架构更改确实很古怪,我们可能希望安排短暂的停机时间。)
回答
几乎是Lot105所描述的。
每个迁移都需要一个Apply和Rollback脚本,并且我们拥有某种控制脚本,该脚本检查需要应用哪些迁移并以适当的顺序应用它们。
然后,每个开发人员都使用此方案使他们的数据库保持同步,并在应用于生产时应用相关更改。如果有必要,可以保留回滚脚本以撤消更改。
使用简单的ALTER脚本无法完成某些更改,例如sqldiff之类的工具会产生这种变化。有些更改不需要架构更改,而需要以编程方式更改现有数据。因此,我们不能一概而论,这就是为什么需要人工编辑的脚本的原因。
回答
我一直希望开发站点指向与实时站点相同的数据库。乍一看这听起来有些冒险,但实际上它解决了许多问题。如果我们在同一服务器上有两个指向同一数据库的站点,则可以实时,准确地查看用户上线后的视图。
我们将永远只有1个数据库,并且只要我们制定一项永不从表中删除列的策略,就知道新代码将与我们正在使用的数据库匹配。
迁移时的破坏也大大减少了。我们只需要移动PHP脚本,并且已经使用相同的DB对它们进行了测试。
我也倾向于创建指向用户上传目标的任何文件夹的符号链接。这意味着不会混淆哪些用户文件已被更新。
另一个副作用是可以选择迁移到一小组" beta测试人员"以在日常使用中使用该网站。这可以导致我们可以在公开发布之前实施许多反馈。
这可能并非在所有情况下都有效,但是我已经开始将所有更新移至该模型。它使开发和发布更加顺畅。
回答
我使用的解决方案(最初是由我的一个朋友开发的)是yukondude的另一个附录。
- 在版本控制下创建一个架构目录,然后为每个数据库更改创建一个.sql文件,其中包含要执行的SQL和sql查询以更新db_schema表。
- 创建一个名为" db_schema"的数据库表,其中包含一个名为version的整数列。
- 在模式目录中,创建两个外壳程序脚本,"当前"和"更新"。执行current会告诉我们连接到的数据库当前处于哪个版本的db模式。运行更新将顺序执行每个编号大于db_schema表中版本的.sql文件,直到我们使用到架构目录中编号最大的文件为止。
模式目录中的文件:
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中。并提示输入正在执行的每个文件的密码。