Identiteta vrstice
Identiteta vrstice določa, kako merql povezuje vrstice med posnetki. Pri primerjavi osnovne različice z našo mora vedeti, da je vrstica X v osnovni različici ista logična vrstica kot vrstica Y v naši, tudi če so se nekatere vrednosti stolpcev spremenile. Pravilo identitete določa, kateri stolpci sestavljajo ključ vrstice.
use Merql\Identity\PrimaryKeyIdentity;
$identity = new PrimaryKeyIdentity(['id']);
$key = $identity->key(['id' => 42, 'title' => 'Hello']);
// "42"
Vmesnik RowIdentity
Vse strategije identitete implementirajo dve metodi:
interface RowIdentity
{
public function key(array $row): string;
public function columns(): array;
}
key() iz podatkov vrstice izdela enolični identifikator v obliki niza. columns() vrne imena stolpcev, uporabljenih za identifikacijo.
PrimaryKeyIdentity
Privzeta strategija. Poveže vrstice glede na njihove stolpce primarnega ključa.
use Merql\Identity\PrimaryKeyIdentity;
// Single-column PK.
$identity = new PrimaryKeyIdentity(['id']);
$key = $identity->key(['id' => 42, 'title' => 'Hello']);
// "42"
// Composite PK.
$identity = new PrimaryKeyIdentity(['tenant_id', 'user_id']);
$key = $identity->key(['tenant_id' => 1, 'user_id' => 99, 'name' => 'Alice']);
// "1\x1F99" (unit separator between parts)
To je privzeta strategija, ki jo uporablja merql, kadar ima tabela v shemi določen primarni ključ.
NaturalKeyIdentity
Pri tabelah brez primarnega ključa s samodejnim povečevanjem poveže vrstice glede na stolpce omejitve enoličnosti. Uporabno, kadar je PK UUID ali kadar tabela kot logično identiteto uporablja sestavljeno omejitev enoličnosti.
use Merql\Identity\NaturalKeyIdentity;
$identity = new NaturalKeyIdentity(['email']);
$key = $identity->key(['id' => 1, 'email' => 'alice@example.com', 'name' => 'Alice']);
// "alice@example.com"
$identity = new NaturalKeyIdentity(['country', 'postal_code']);
$key = $identity->key(['country' => 'US', 'postal_code' => '90210', 'city' => 'Beverly Hills']);
// "US\x1F90210"
ContentHashIdentity
Rezervna možnost za tabele brez primarnega ključa in omejitev enoličnosti. Izračuna zgoščeno vrednost SHA-256 vseh vrednosti stolpcev. Vrstici sta enaki, če se ujemajo vsi stolpci.
use Merql\Identity\ContentHashIdentity;
$identity = new ContentHashIdentity(['name', 'value']);
$key = $identity->key(['name' => 'color', 'value' => 'blue']);
// "a3f2..." (SHA-256 hash)
Identifikacija z zgoščeno vrednostjo vsebine ima omejitev: če se vsebina vrstice spremeni, se spremeni tudi njena zgoščena vrednost, zato je vrstica prikazana kot izbris stare zgoščene vrednosti in vstavljanje nove, namesto kot posodobitev. To je neizogiben kompromis, kadar ni stabilnih stolpcev identitete.
IdentityRule
IdentityRule je serializabilna konfiguracija identitete, ki jo uporabljata zajem posnetka
in načrti združevanja.
use Merql\Identity\IdentityRule;
$rule = IdentityRule::natural(['option_name']);
$key = $rule->key(['option_name' => 'siteurl']);
// "siteurl"
Vrste pravil:
| Vrsta | Pomen |
|---|---|
primary |
Stolpci primarnega ključa podatkovne zbirke |
natural |
Stabilni enolični poslovni stolpci |
composite |
Stolpci sestavljene logične identitete |
content |
Rezervna možnost z zgoščeno vrednostjo vsebine |
IdentityRule::forSchema($schema) določi privzeto pravilo:
- Če ima tabela primarni ključ, uporabi stolpce primarnega ključa.
- Če ima tabela enolične ključe, uporabi stolpce prvega enoličnega ključa.
- Če nima nobenega od njih, uporabi vse stolpce (rezervna možnost z zgoščeno vrednostjo vsebine).
IdentityRuleSet
Uporabite IdentityRuleSet, kadar gostiteljska aplikacija pozna boljše pravilo identitete kot
privzeto pravilo sheme.
use Merql\Identity\IdentityRule;
use Merql\Identity\IdentityRuleSet;
use Merql\Snapshot\Snapshotter;
$rules = new IdentityRuleSet([
'wp_options' => IdentityRule::natural(['option_name']),
'wp_term_relationships' => IdentityRule::composite(['object_id', 'term_taxonomy_id']),
]);
$snapshotter = new Snapshotter($connection, identityRules: $rules);
$snapshot = $snapshotter->capture('live', ['wp_options', 'wp_term_relationships']);
Snapshotter za vsako zajeto tabelo določi IdentityRule.
Izbrani stolpci so shranjeni v TableSnapshot::identityColumns in uporabljeni pri vseh
nadaljnjih operacijah diff, merge, plan, SQL in rollback.
Merql::init() lahko prejme isti nabor pravil tudi pri uporabi statičnega vmesnika:
use Merql\Merql;
Merql::init($connection, identityRules: $rules);
Merql::snapshot('live', ['wp_options']);
Nabori pravil imajo stabilno serializacijo polj:
$payload = $rules->toArray();
$rules = IdentityRuleSet::fromArray($payload);
Neenolična identiteta
Če imata dve zajeti vrstici isti ključ identitete, zajem ne uspe, namesto da bi eno vrstico prepisal z drugo.
use Merql\Exceptions\SnapshotException;
try {
$snapshotter->capture('live', ['wp_postmeta']);
} catch (SnapshotException $e) {
// The configured identity rule matched multiple rows.
}
Gostiteljske aplikacije lahko pred zajemom preverijo surove vrstice z IdentityRuleSet::conflictsFor(),
če želijo neenoličnost zaznati še pred zajemom:
$conflicts = $rules->conflictsFor(
'wp_postmeta',
IdentityRule::natural(['post_id', 'meta_key']),
$rows,
);
Za WordPress-jeve metatabele je post_id + meta_key običajno uporaben za združevanje v skupine
in prikaz, ni pa varen za identifikacijo vrstic, ker so podvojeni ključi meta veljavni.
Za identiteto vrstice uporabite primarni ključ tabele, razen če lahko gostiteljska
aplikacija dokaže, da je naravni ključ enoličen.
Kodiranje ključa vrstice
Ključi vrstic so kodirani nizi, ki združujejo vrednosti več stolpcev z ločilom enote (\x1F). Vrednosti, ki vsebujejo ločilo ali znak za odstotek, so ubežno kodirane, da se preprečijo kolizije:
use Merql\Snapshot\Snapshotter;
// Encode.
$key = Snapshotter::buildRowKey(
['tenant_id' => '1', 'user_id' => '99'],
['tenant_id', 'user_id'],
);
// "1\x1F99"
// Decode.
$parts = Snapshotter::decodeRowKey($key);
// ['1', '99']
Pravila ubežnega kodiranja:
| Izvirnik | Ubežano |
|---|---|
% |
%25 |
\x1F (ločilo enot) |
%1F |
To zagotavlja, da se vrednost, ki vsebuje \x1F, ne razdeli na več delov ključa. Kodiranje je deterministično in reverzibilno.
Razhajanje samodejnega povečevanja
Ko obe strani vstavita nove vrstice, se ID-ji samodejnega povečevanja med vejami razlikujejo. Vrstica #100 v naši kopiji je lahko povsem drug zapis kot vrstica #100 v njihovi kopiji.
merql to obravnava tako, da primerja primarne ključe. Če obe strani vstavita vrstico z istim ID-jem samodejnega povečevanja, je označena kot spor insert_insert. Da bi se temu izognili, za tabele, v katere se pričakujejo sočasni vnosi, uporabite naravne ključe (enolične stolpce, ki so stabilni med vejami).
// A natural key on (slug) avoids auto-increment collisions.
$identity = new NaturalKeyIdentity(['slug']);
Identiteta v posnetkih
Stolpci identitete, izbrani med zajemom, so shranjeni z vsakim TableSnapshot:
$tableSnapshot = $snapshot->getTable('posts');
$tableSnapshot->identityColumns;
// ['id']
Ti stolpci se uporabljajo za SqlGenerator za tvorjenje stavkov WHERE za UPDATE in DELETE, načrti združevanja pa z njimi prikažejo dekodirane vrednosti identitete za pregled, izbiro, varovano uporabo in povrnitev.