Aloitus
Tässä oppaassa käydään läpi asennus, tietokantaan yhdistäminen, tilannevedosten tallentaminen, erojen laskeminen ja kolmen osapuolen yhdistäminen.
Asennus
composer require merql/merql
merql vaatii PHP 8.2:n tai uudemman sekä ext-mbstring- ja ext-zlib-laajennukset (molemmat pitmaster/pitmaster-riippuvuuden vaatimia). Tarvitset myös käyttämäsi sovittimen laajennuksen: PDO-sovitinta varten ext-pdo sekä ext-pdo_sqlite tai ext-pdo_mysql, mysqli-sovitinta varten ext-mysqli. Composer ainoastaan ehdottaa näitä, joten tarkista, että tarvitsemasi laajennus on asennettu.
Paketti asentaa CLI-ohjelman nimellä vendor/bin/merql. Käytä merql-versiota 0.4.1 tai uudempaa CLI-ohjelmaa varten; aiemmissa versioissa suoritettava tiedosto ei löytänyt automaattisesti ladattavaa tiedostoa, kun merql oli asennettu riippuvuutena.
Tietokantaan yhdistäminen
merql toimii pienen yhteyssovittimen rajapinnan kautta. Mukana on sisäänrakennetut sovittimet PDO:lle ja mysqlille sekä murreajurit kohteille MySQL ja SQLite.
use Merql\Connection;
// SQLite (in-memory or file-based, through PDO).
$connection = Connection::sqlite(':memory:');
$connection = Connection::sqlite('/path/to/database.sqlite');
// MySQL through PDO.
$connection = Connection::mysql('127.0.0.1', 'my_database', 'root', 'password');
// MySQL through mysqli.
$connection = Connection::mysqli('127.0.0.1', 'my_database', 'root', 'password');
// Any MySQL or SQLite PDO DSN.
$connection = Connection::fromDsn('mysql:host=127.0.0.1;dbname=my_database;charset=utf8mb4', 'root', 'password');
fromDsn() avaa minkä tahansa PDO:n tukeman DSN:n, mutta merql sisältää murreajurit vain kohteille MySQL ja SQLite. Jos käytät muuta tietokantamoottoria, kuten pgsql:, yhteys avautuu, mutta Merql::init() heittää poikkeuksen Unsupported database driver: pgsql, kunnes rekisteröit sille ajurin. Katso Tietokanta-ajurit.
Tilannevedoksen tallentaminen
Tilannevedos tallentaa jokaisen rivin jokaisesta taulusta (tai taulujen osajoukosta) sormenjälkinä ja tietoina. Sormenjäljet mahdollistavat nopean muutosten havaitsemisen; koko rivin tiedot ovat käytettävissä, kun eroja tarvitaan.
use Merql\Merql;
Merql::init($connection);
// Snapshot all tables.
$snapshot = Merql::snapshot('baseline');
// Snapshot specific tables.
$snapshot = Merql::snapshot('baseline', ['posts', 'comments', 'users']);
Tilannevedokset tallennetaan oletusarvoisesti JSON-tiedostoina sijaintiin .merql/snapshots/. Voit vaihtaa sijaintia:
use Merql\Snapshot\SnapshotStore;
SnapshotStore::setDirectory('/var/data/merql-snapshots');
Erojen laskeminen
Erovertailu vertaa kahta tilannevedosta ja palauttaa muutossarjan, joka sisältää lisäykset, päivitykset ja poistot. Molempien tilannevedosten on oltava olemassa; tässä current on toinen tilannevedos, joka tallennettiin tietokannan muutosten jälkeen.
$changeset = Merql::diff('baseline', 'current');
echo "Inserts: " . count($changeset->inserts()) . "\n";
echo "Updates: " . count($changeset->updates()) . "\n";
echo "Deletes: " . count($changeset->deletes()) . "\n";
// Inspect changes for a single table.
$postChanges = $changeset->forTable('posts');
// Check per-column diffs on updates.
foreach ($changeset->updates() as $update) {
echo "Row {$update->rowKey} in {$update->table}:\n";
foreach ($update->columnDiffs as $diff) {
echo " {$diff->column}: {$diff->oldValue} -> {$diff->newValue}\n";
}
}
Kolmen osapuolen yhdistäminen
Keskeinen toiminto. Ottaa kolme nimettyä tilannevedosta (base, ours, theirs) ja yhdistää kaksi muutosjoukkoa.
Base on tila, josta molemmat kopiot lähtivät. Ours ja theirs ovat kaksi kopiota sen jälkeen, kun niitä on muutettu itsenäisesti, joten kummastakin on tallennettava tilannevedos sen sisältävästä tietokannasta. Esimerkiksi, kun testiympäristö kopioitiin tuotantotietokannasta:
use Merql\Connection;
use Merql\Merql;
$live = Connection::sqlite('/data/live.sqlite');
$sandbox = Connection::sqlite('/data/sandbox.sqlite');
Merql::init($live);
Merql::snapshot('base'); // before the sandbox is copied from live
// ... copy live.sqlite to sandbox.sqlite, then both databases change ...
Merql::init($sandbox);
Merql::snapshot('ours'); // the sandbox with our edits
Merql::init($live);
Merql::snapshot('theirs'); // live with its own changes
$result = Merql::merge('base', 'ours', 'theirs');
echo "Operations: {$result->operationCount()}\n";
echo "Conflicts: {$result->conflictCount()}\n";
echo "Clean: " . ($result->isClean() ? 'yes' : 'no') . "\n";
Älä ota kaikkia kolmea tilannevedosta samasta tietokannasta peräkkäin. Tällöin theirs sisältäisi jo ours-muutokset, ja jokainen ours-puolen lisäämä rivi näkyisi insert_insert-ristiriitana.
Merql::merge() yhdistää sarakkeiden tasolla. Jos haluat yhdistää myös TEXT- ja JSON-arvojen sisäisiä muutoksia, käytä ThreeWayMerge-asetusta ja CellMergeConfig-valitsinta; katso Solutason yhdistäminen.
Ristiriitojen käsittely
Kun molemmat puolet muuttavat saman sarakkeen eri arvoiksi, merql ilmoittaa ristiriidasta. Voit ratkaista ristiriidat automaattisesti tai tarkastella niitä itse.
use Merql\Merge\ConflictPolicy;
use Merql\Merge\ConflictResolver;
if (!$result->isClean()) {
// Auto-resolve: one side wins.
$resolved = ConflictResolver::resolve($result, ConflictPolicy::TheirsWins);
// Or inspect each conflict.
foreach ($result->conflicts() as $conflict) {
echo "Conflict on {$conflict->table()} row {$conflict->rowKey()}:\n";
echo " Type: {$conflict->type()}\n";
echo " Column: {$conflict->column()}\n";
echo " Ours: " . var_export($conflict->oursValue(), true) . "\n";
echo " Theirs: " . var_export($conflict->theirsValue(), true) . "\n";
}
}
Yhdistämisen käyttäminen
Kun yhdistämistulos on puhdas (ristiriitoja ei ole ratkaisematta), käytä sitä tietokantaan, joka välitettiin komennolle Merql::init().
Yhdistämistuloksen toiminnot muuttavat basen yhdistetyksi tilaksi ja sisältävät molempien puolten muutokset. Merql::apply() suorittaa ne kaikki, joten tulos soveltuu sellaisenaan tietokantaan, jossa on yhä base-tila. Jos sitä käytetään tietokantaan, joka sisältää jo toisen puolen muutokset, kyseisen puolen lisäämä rivi on jo olemassa, lisäys epäonnistuu ja koko yhdistäminen perutaan. Jos haluat siirtää toisen puolen muutokset tietokantaan, jossa on jo toisen puolen muutokset (esimerkiksi testiympäristön muutokset tuotantoon), käytä vain puuttuvia toimintoja komennolla Suojattu käyttö.
$applied = Merql::apply($result);
echo "Rows affected: {$applied->rowsAffected()}\n";
if ($applied->hasErrors()) {
foreach ($applied->errors() as $error) {
echo "Error: {$error}\n";
}
}
Soveltaja käärii kaikki toiminnot transaktioon. Jos jokin lause epäonnistuu, koko yhdistäminen perutaan ja virhe palautetaan kohteessa errors(). Tällöin rowsAffected() sisältää silti ennen virhettä suoritettujen lauseiden määrän, vaikka ne peruttiin (#4); tarkista ensin hasErrors().
Koesuoritus
Esikatsele SQL, jonka yhdistäminen tuottaisi, suorittamatta sitä.
use Merql\Apply\DryRun;
$statements = DryRun::generate($result);
foreach ($statements as $sql) {
echo "{$sql};\n";
}
Kahden osapuolen korjaus
Jos käytettävissäsi on vain base ja joukko muutoksia (ei rinnakkaisia "ours"-muutoksia), käytä patch(). Tämä vastaa yhdistämistä, jossa ours on muuttumaton baseen nähden.
$result = Merql::patch('base', 'changes');
// Always clean: no concurrent edits means no conflicts.
Merql::apply($result);
CLI-ohjelman käyttö
Kaikki nämä toiminnot ovat käytettävissä myös komentoriviltä. Katso CLI-ohjelman viite, josta löydät kaikki tiedot.
export MERQL_DB_DSN="sqlite:mydb.sqlite"
vendor/bin/merql snapshot base
# ... change the database ...
vendor/bin/merql snapshot current
vendor/bin/merql diff base current
Tee kolmen osapuolen yhdistämistä varten kukin tilannevedos sen tilan sisältävästä tietokannasta ja yhdistä sitten:
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot base
MERQL_DB_DSN="sqlite:/data/sandbox.sqlite" vendor/bin/merql snapshot ours
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot theirs
vendor/bin/merql merge base ours theirs --dry-run
Taulujen ja sarakkeiden suodattaminen
Tilannevedoksista voi jättää pois tauluja (kuten välimuisti- tai istuntotaulut) ja sivuuttaa muuttuvia sarakkeita (kuten updated_at-aikaleimoja).
use Merql\Filter\TableFilter;
use Merql\Filter\ColumnFilter;
use Merql\Snapshot\Snapshotter;
$snapshotter = new Snapshotter($connection);
$snapshot = $snapshotter->capture('baseline', filters: [
TableFilter::exclude(['sessions', 'cache_*']),
ColumnFilter::ignore(['updated_at', 'modified_date']),
]);
Seuraavat vaiheet
- CLI-ohjelman viite sisältää komentorivikäyttöliittymän kaikki tiedot.
- PHP API-viite sisältää kaikkien luokkien ja metodien yksityiskohtaiset ohjeet.