php - tutorial - Migración de cambios en la base de datos del desarrollo a la vida
the django project (10)
No confío en las migraciones programáticas. Si se trata de un cambio simple, como agregar una columna NULLable, simplemente lo agregaré directamente al servidor en vivo. Si es más complejo o requiere cambios de datos, escribiré un par de archivos de migración de SQL y los probaré contra una base de datos de réplicas.
Cuando use migraciones, siempre pruebe la migración de reversión. Es su botón de emergencia "oh mierda".
Quizás el mayor riesgo para impulsar nuevas funcionalidades para la vida reside en las modificaciones de la base de datos requeridas por el nuevo código. En Rails, creo que tienen ''migraciones'', en las que puede realizar cambios programáticos en su host de desarrollo y luego hacer los mismos cambios en vivo junto con el código que usa el esquema revisado. Y tira los dos hacia atrás si es necesario, de forma sincronizada.
¿Alguien ha encontrado un conjunto de herramientas similar para PHP / MySQL? Me encantaría saber al respecto, o cualquier solución programática o de proceso para ayudar a que esto sea menos riesgoso ...
Nunca me encontré con una herramienta que hiciera el trabajo. En su lugar, he utilizado archivos individuales, numerados para que sepa qué orden ejecutar: básicamente, una versión manual de las migraciones de Rails, pero sin la reversión.
Aquí está el tipo de cosas de las que estoy hablando:
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...
Nunca he tenido problemas para hacer esto, pero no es muy elegante. Depende de usted rastrear qué scripts necesitan ejecutarse para una actualización dada (un esquema de numeración más inteligente podría ayudar). También funciona bien con control de fuente.
Tratar con los valores clave sustitutos (de las columnas de autonumeración) puede ser complicado, ya que la base de datos de producción probablemente tendrá valores diferentes a los de la base de datos de desarrollo. Por lo tanto, intento nunca hacer referencia a un valor de clave sustituta literal en ninguno de mis scripts de modificación, si es posible.
Symfony tiene un complemento llamado sfMigrationsLight que maneja las migraciones básicas. CakePHP también tiene migraciones.
Por alguna razón, el apoyo a la migración nunca ha sido una prioridad para la mayoría de los marcos PHP y ORM que existen.
@ [yukondude]
Estoy usando Perl, y he bajado la ruta de las migraciones estilo Rails de forma semi manual de la misma manera.
Lo que hice fue tener una sola tabla "versión" con una única columna "versión", que contiene una sola fila de un número que es la versión actual del esquema. Luego fue (bastante) trivial escribir un script para leer ese número, buscar en un directorio determinado y aplicar todas las migraciones numeradas para ir desde allí hasta aquí (y luego actualizar el número).
En mi entorno dev / stage, con frecuencia (a través de otro script) extraigo los datos de producción en la base de datos provisional y ejecuto el script de migración. Si haces esto antes de lanzar, estarás bastante seguro de que las migraciones funcionarán. Obviamente, prueba extensivamente en su entorno de ensayo.
Etiqueto el nuevo código y las migraciones requeridas bajo una etiqueta de control de versión. Para implementar en vivo o por etapas, simplemente actualice todo a esta etiqueta y ejecute el script de migración con bastante rapidez. (Es posible que desee haber arreglado un tiempo de inactividad corto si realmente se trata de cambios de esquema extravagantes).
He usado esta herramienta antes y funcionó perfectamente.
Toma como entrada una conexión de base de datos o un archivo de SQL, y lo compara con el mismo (ya sea otra conexión de base de datos u otro archivo de SQL). Puede escupir el SQL para realizar los cambios o hacer los cambios por usted.
Más o menos lo que Lot105 describió.
Cada migración necesita una secuencia de comandos de aplicación y retrotracción, y usted tiene algún tipo de secuencia de comandos de control que verifica qué migración (es) deben aplicarse y las aplica en el orden apropiado.
Cada desarrollador entonces mantiene su base de datos sincronizada utilizando este esquema, y cuando se aplica a la producción se aplican los cambios pertinentes. Los scripts de retrotracción se pueden mantener para revertir un cambio si es necesario.
Algunos cambios no se pueden hacer con un simple script ALTER tal como una herramienta como sqldiff produciría; algunos cambios no requieren un cambio de esquema, sino un cambio programático de los datos existentes. Por lo tanto, no se puede generalizar, por lo que se necesita una secuencia de comandos editada por humanos.
Siempre he preferido mantener mi sitio de desarrollo apuntando a la misma base de datos que el sitio en vivo. Esto puede sonar arriesgado al principio, pero en realidad resuelve muchos problemas. Si tiene dos sitios en el mismo servidor que apuntan a la misma base de datos, obtendrá una vista en tiempo real y precisa de lo que verán los usuarios cuando entre en funcionamiento.
Solo tendrá 1 base de datos y, siempre que establezca como política no eliminar nunca una columna de una tabla, sabrá que su nuevo código coincidirá con la base de datos que está utilizando.
También hay mucho menos estragos al migrar. Solo necesita moverse sobre los scripts de PHP y ya están probados usando el mismo DB.
También tiendo a crear un enlace simbólico a cualquier carpeta que sea un objetivo para cargas de usuarios. Esto significa que no hay confusión sobre qué archivos de usuario se han actualizado.
Otro efecto secundario es la opción de transferir un pequeño grupo de ''beta-testers'' para utilizar el sitio en el uso diario. Esto puede generar muchos comentarios que puede implementar antes del lanzamiento público.
Es posible que esto no funcione en todos los casos, pero he comenzado a mover todas mis actualizaciones a este modelo. Ha causado un desarrollo y lanzamientos mucho más suaves.
En el pasado he usado LiquiBase , una herramienta basada en Java donde configura sus migraciones como archivos XML. Puede generar el SQL necesario con él.
Hoy utilizaría la biblioteca Doctrine 2 , que tiene instalaciones de migración similares a Ruby.
El marco Symfony 2 también tiene una buena manera de lidiar con los cambios de esquema: su herramienta de línea de comandos puede analizar el esquema existente y generar SQL para que coincida con las definiciones de esquema modificadas.
La solución que uso (originalmente desarrollada por un amigo) es otra adición a yukondude.
- Cree un directorio de esquema bajo control de versión y luego, para cada cambio de db, mantenga un archivo .sql con el SQL que desea ejecutar junto con la consulta sql para actualizar la tabla db_schema.
- Cree una tabla de base de datos llamada "db_schema" con una columna entera llamada versión.
- En el directorio de esquema, cree dos scripts de shell, "actual" y "actualizar". La ejecución actual le dice a qué versión del esquema db está actualmente la base de datos a la que está conectado. La ejecución de la actualización ejecuta cada archivo .sql numerado de forma mayor a la versión en la tabla db_schema hasta que alcanza el archivo numerado más grande en su directorio de esquema.
Archivos en el dir del esquema:
0-init.sql 1-add-name-to-user.sql 2-add-bio.sql
Como es un archivo típico, observe la actualización de db_schema al final de cada archivo .sql:
BEGIN;
-- comment about what this is doing
ALTER TABLE user ADD COLUMN bio text NULL;
UPDATE db_schema SET version = 2;
COMMIT;
El script "actual" (para 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
el script de actualización (también 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
Mi 0-init.sql tiene la estructura de esquema inicial completa junto con la versión inicial "UPDATE db_schema SET version = 0;". No debería ser demasiado difícil modificar estos scripts para MySQL. En mi caso, también tengo
export PGDATABASE="dbname" export PGUSER="mike"
en mi .bashrc. Y solicita una contraseña con cada archivo que se está ejecutando.
Yo uso SQLyog para copiar la estructura, y SIEMPRE, permítanme repetir SIEMPRE hacer una copia de seguridad primero.