0 follower

Databasmigrering

MÀrk: Finessen databasmigrering har varit tillgÀnglig sedan version 1.1.6.

Likt kÀllkod vidareutvecklas strukturen för en databas över tid under utveckling och förvaltning av en databasdriven applikation. Till exempel under pÄgÄende utveckling, kan vi behöva lÀgga till en ny tabell; nÀr applikationen gÄtt i produktion kan vi upptÀcka behov av att lÀgga till ett index för en kolumn. Dat Àr viktigt att hÄlla reda pÄ sÄdana strukturella databasÀndringar (benÀmnda migration), sÄ som vi gör med vÄr kÀllkod. Om kÀllkod och databas kommer ur synk, Àr det mycket sannolikt att hela systemet kan fallera. Av denna anledning tillhandahÄller Yii ett verktyg för databasmigrering som kan hÄlla reda pÄ historik för datamigrering, applicera nya migreringar, eller ÄterstÀlla sÄdana som gjorts tidigare.

Följande steg belyser hur databasmigrering kan anvÀndas under utvecklingens gÄng:

  1. Tim skapar en ny migrering (t.ex. skapa en ny tabell)
  2. Tim fastlÀgger (commits) den nya migreringen i versionshanteringssystemet (t.ex. SVN, GIT)
  3. Doug uppdaterar frÄn versionshanteringssystemet och tar emot den nya migreringen
  4. Doug applicerar migreringen pÄ sin lokala utvecklingsdatabas

Yii stöder databasmigrering via kommandoradsverktyget yiic migrate. Detta verktyg har stöd för att skapa nya migreringar, applicera/ÄterstÀlla/upprepa migreringar samt för att visa migreringshistorik och nya migreringar.

I det följande kommer vi att visa hur detta verktyg anvÀnds.

MÀrk: Det Àr bÀttre att anvÀnda applikationens instans av yiic (t.ex. cd path/to/protected) vid arbete med migrate-kommandot, i stÀllet för den i framework-katalogen. Kontrollera att katalogen protected\migrations existerar och Àr möjlig att skriva till, samt att en databasanslutning Àr konfigurerad i protected/config/console.php.

1. Skapa migreringar ¶

För att skapa en ny migrering (t.ex. skapa tabellen news), kör vi följande kommando:

yiic migrate create <name>

Den obligatoriska name-parametern specificerar en mycket kortfattad beskrivning av migreringen (t.ex. create_news_table). Nedan framgÄr det att name-parametern kommer att anvÀndas som en del i ett PHP-klassnamn. DÀrför skall den bara innehÄlla bokstÀver, siffror och/eller understrykningstecken.

yiic migrate create create_news_table

OvanstÄende kommando kommer att, i katalogen protected/migrations, skapa en ny fil med namnet m101129_185401_create_news_table.php vilken innehÄller följande initiala kod:

class m101129_185401_create_news_table extends CDbMigration
{
    public function up()
    {
    }
 
    public function down()
    {
        echo "m101129_185401_create_news_table does not support migration down.\n";
        return false;
    }
 
    /*
    // implementera safeUp/safeDown i stÀllet, om transaktioner skall anvÀndas
    public function safeUp()
    {
    }
 
    public function safeDown()
    {
    }
    */
}

LÀgg mÀrke till att klassnamnet Àr samma som filnamnet enligt mönstret m<timestamp>_<name>, dÀr <timestamp> refererar till UTC-tidstÀmpeln för nÀr migreringen skapats (pÄ formatet yymmdd_hhmmss), och <name> hÀmtas frÄn kommandots name-parameter.

Metoden up() skall innehÄlla koden som implementerar den aktuella databasmigreringen, medan metoden down() kan innehÄlla kod för att ÄterstÀlla det som sker i up().

Ibland Àr det inte möjligt att implementera down(). Om vi exempelvis tar bort tabellrader i up(), kommer vi inte att kunna ÄterstÀlla dem i down(). I sÄdant fall kallas migreringen irreversibel, med innebörden att vi inte kan backa till ett tidigare tillstÄnd för databasen. I den generarade koden ovan, returnerar metoden down() vÀrdet false som indikation att migreringen inte Àr reversibel.

Info: Med start frÄn version 1.1.7 gÀller att returvÀrdet false frÄm metoderna up() och down() medför att efterföljande migreringar annulleras. Tidigare, i version 1.1.6, krÀvdes att man genererade en exception för att övriga migreringar skulle annulleras.

Tag som exempel migreringen att skapa en news-tabell.

class m101129_185401_create_news_table extends CDbMigration
{
    public function up()
    {
        $this->createTable('tbl_news', array(
            'id' => 'pk',
            'title' => 'string NOT NULL',
            'content' => 'text',
        ));
    }
 
    public function down()
    {
        $this->dropTable('tbl_news');
    }
}

Basklassen CDbMigration erbjuder en uppsÀttning metoder för manipulering av data och databasens schema. Till exempel, CDbMigration::createTable skapar en databastabell, medan CDbMigration::insert lÀgger till en rad med data. Dessa metoder anvÀnder alla databasanslutningen som returneras av CDbMigration::getDbConnection(), som standard Yii::app()->db.

Info: Noterbart Àr att databasmetoderna som CDbMigration erbjuder Àr mycket lika de i CDbCommand. Faktiskt sÄ Àr de likadana med undantaget att CDbMigration-metoderna mÀter tidÄtgÄng och skriver ut nÄgra meddelanden om metodparametrarna.

2. Transaktionella migreringar ¶

Info: Finessen transaktionella migreringar stöds sedan version 1.1.7.

Vid genomförande av komplexa DB-migreringar vill vi vanligen försÀkra oss om att samtliga migreringssteg utförs korrekt eller fallerar som en enhet, sÄ att databasen upprÀtthÄller korrekthet och integritet. För att uppnÄ detta mÄl kan vi dra nytta av DB-transaktioner.

Vi kan uttryckligen starta en DB-transaktion och lÄta transaktionen omge resterande DB-relaterad kod, pÄ följande sÀtt:

class m101129_185401_create_news_table extends CDbMigration
{
    public function up()
    {
        $transaction=$this->getDbConnection()->beginTransaction();
        try
        {
            $this->createTable('tbl_news', array(
                'id' => 'pk',
                'title' => 'string NOT NULL',
                'content' => 'text',
            ));
            $transaction->commit();
        }
        catch(Exception $e)
        {
            echo "Exception: ".$e->getMessage()."\n";
            $transaction->rollBack();
            return false;
        }
    }
 
    // ...liknande kod för down()
}

Ett enklare sÀtt att erhÄlla transaktionsstöd Àr att implementera metoden safeUp() i stÀllet för up(), och metoden safeDown() i stÀllet för down(). Till exempel,

class m101129_185401_create_news_table extends CDbMigration
{
    public function safeUp()
    {
        $this->createTable('tbl_news', array(
            'id' => 'pk',
            'title' => 'string NOT NULL',
            'content' => 'text',
        ));
    }
 
    public function safeDown()
    {
        $this->dropTable('tbl_news');
    }
}

NÀr migreringen utförs kommer Yii att starta en DB-transaktion och dÀrefter anropa safeUp() eller safeDown(). Om nÄgot DB-fel intrÀffar i safeUp() eller safeDown(), kommer transaktionen att reverseras och dÀrmed
sÀkerstÀlla att databasen förblir i ett gott skick.

MÀrk: Transaktioner stöds inte av alla databashanterare. Vissa DB-frÄgor kan inte ingÄ i en transaktion. I sÄdant fall mÄste i stÀllet up() och down() implementeras. I frÄga om MySQL, kan vissa SQL-satser leda till en underförstÄdd commit-operation.

3. Applicera migreringar ¶

För att applicera alla tillgÀngliga nya migreringar (dvs göra den lokala databasen helt up-to-date), kör följande kommando:

yiic migrate

Kommandot kommer att presentera en lista över alla nya migreringar. Efter bekrÀftelse att migreringarna skall appliceras, kommer metoden up() i varje ny migreringsklass att exekveras, en efter en, i den ordning tidstÀmpelvÀrden i klassnamnen anger.

Efter applicering av en migrering kommer migreringsverktyget att spara en post i databastabellen tbl_migration. Detta möjliggör för vektyget att hÄlla reda pÄ vilka migreringar som applicerats och vilka som inte har applicerats. Om tabellen tbl_migration inte existerar, kommer verktyget att automatiskt skapa den i databasen som specificeras av applikationskomponenten db.

Ibland vill vi bara applicera en eller ett fÄtal nya migreringar. Följande kommando kan dÄ anvÀndas:

yiic migrate up 3

Detta kommando applicerar tre nya migreringar. Genom att Àndra vÀrdet (3) kan vi Àndra antalet migreringar som skall appliceras.

Vi kan Àven migrera databasen till en specifik version, med följande kommando:

yiic migrate to 101129_185401

Det vill sÀga, vi anvÀnder tidstÀmpeldelen av migreringens namn för att specificera den version vi vill migrera databasen till. Om det finns flera migreringar mellan den senast applicerade och den specificerade migreringen kommer samtliga dessa migreringar att appliceras. Om den specificerade migreringen redan har applicerats tidigare, kommer alla migreringar som applicerats dÀrefter att ÄterstÀllas (kommer att beskrivas i nÀsta avsnitt).

4. ÅterstĂ€lla migreringar ¶

För att backa tillbaka den senaste eller flera applicerade migreringar, kan följande kommando anvÀndas:

yiic migrate down [step]

dÀr den frivilliga step-parametern specificerar antalet migreringar som skall backas tillbaka. Som standard Àr den 1, vilket innebÀr att den senaste migreringen backas.

Som tidigare beskrivits kan inte alla migreringar backas. Försök att backa irreversibla migreringar kommer att generera ett undantag och innebÀr att hela ÄterstÀllningsprocessen stoppas.

5. Göra om migreringar ¶

Att göra om migreringar innebÀr att först backa och sedan pÄ nytt applicera de specificerade migreringarna. Detta kan göras med följande kommando:

yiic migrate redo [step]

dÀr den frivilliga step-parametern specificerar antalet migreringar som skall göras om. StandardvÀrde 1, med innebörden att göra om den senaste migreringen.

6. Visa information om migreringar ¶

Utöver att applicera och backa tillbaka migreringar, kan migreringsverktyget Àven presentera migrationshistorik och de nya migreringar som vÀntar pÄ att appliceras.

yiic migrate history [limit]
yiic migrate new [limit]

dÀr den frivilliga parametern limit specificerar antalet migreringar som skall visas. Om limit utelÀmnas, kommer samtliga tillgÀngliga migreringar att visas.

Det första kommandot visar de migeringar som har applicerats medan det andra kommandot visar de migreringar som Ànnu ej applicerats.

7. Modifiera migreringshistorik ¶

Ibland kan vi ha för avsikt att Àndra migreringshistoriken till en specifik version, utan att faktiskt applicera eller backa tillbaka de relevanta migreringarna. Detta intrÀffar ofta under utveckling av en ny migrering. Följande kommando kan anvÀndas för detta ÀndamÄl.

yiic migrate mark 101129_185401

Detta kommando Àr snarlikt yiic migrate to-kommandot, med undantag för att det enbart Àndrar tabellen med migreringshistorik till den specificerade versionen utan att applicera eller backa tillbaka migreringarna.

8. Anpassa migreringskommandot ¶

Migreringskommandot kan anpassas pÄ mÄnga sÀtt.

Med alternativ pÄ kommandorad

Migreringskommandot har fyra inbyggda alternativ som kan specificeras pÄ kommandoraden:

  • interactive: boolean, specificerar huruvida migrering skall utföras i interaktivt lĂ€ge. Som standard true, vilket innebĂ€r att anvĂ€ndaren tillfrĂ„gas nĂ€r en specifik migrering skall utföras. SĂ€tt till false i hĂ€ndelse migreringarna skall utföras i en bakgrundsprocess.

  • migrationPath: string, specificerar katalogen som lagrar alla migreringars klassfiler. Detta mĂ„ste specificeras som ett sökvĂ€gsalias och den motsvarande katalogen mĂ„ste existera. Om alternativet utelĂ€mnas kommer underkatalogen migrations till applikationens basePath att anvĂ€ndas.

  • migrationTable: string, specificerar namnet pĂ„ den databastabell som lagrar migreringshistoriken. Som standard Ă€r det tbl_migration. Tabellstrukturen Ă€r version varchar(255) primary key, apply_time integer.

  • connectionID: string, specificerar ID för databasens applikationskomponent. Är som standard 'db'.

  • templateFile: string, specificerar sökvĂ€gen för den fil som skall tjĂ€nsgöra som kodmall för generering av migreringsklasserna. Denna mĂ„ste specificeras som ett sökvĂ€gsalias (t.ex. application.migrations.template). Om alternativet utelĂ€mnas kommer en intern mall att anvĂ€ndas. Inuti kodmallen kommer symbolen {ClassName} att ersĂ€ttas av det faktiska namnet pĂ„ migreringsklassen.

För att specificera dessa alternativ, exekvera migreringskommandot pÄ följande format

yiic migrate up --option1=value1 --option2=value2 ...

Till exempel, om vi vill migrera för en modul forum, vars migreringsfiler Àr placerade i modulens underkatalog migrations, kan vi anvÀnda följande kommando:

yiic migrate up --migrationPath=ext.forum.migrations

Global konfigurering av kommando

Medan kommandoradsalternativ tillÄter oss att konfigurera migreringskommandot i farten, kan vi ibland vilja konfigurera kommandot en gÄng för alla. Till exempel kan vi vilja anvÀnda en annan tabell för lagring av migreringshistoriken, eller vi kanske vill anvÀnda en anpassad migreringsmall. Detta kan vi göra genom att modifiera konsolapplikationens konfigurationsfil sÄ som följer,

return array(
    ......
    'commandMap'=>array(
        'migrate'=>array(
            'class'=>'system.cli.commands.MigrateCommand',
            'migrationPath'=>'application.migrations',
            'migrationTable'=>'tbl_migration',
            'connectionID'=>'db',
            'templateFile'=>'application.migrations.template',
        ),
        ......
    ),
    ......
);

Om vi nu kör migrate-kommandot, kommer ovanstÄende konfigureringar att gÀlla, utan att vi behöver mata in kommandoradsalternativ varje gÄng.

Found a typo, or you think this page needs improvement?
Edit it on GitHub !