İçeriğe geç

Korumalı Uygulama

GuardedApplier, temiz bir MergeResult öğesini yalnızca hedef veritabanı beklenen canlı anlık görüntüyle hâlâ eşleşiyorsa uygular. Bu, birleştirme planı daha önce incelendiğinde ve uygulamadan önce canlı satırlar değişmiş olabileceğinde kullanışlıdır.

Tipik kurulumda bir sanal alanın düzenlemeleri canlı veritabanına aktarılır. Taban, sanal alanın kopyalandığı andaki canlı durumdur; ours düzenlenen sanal alandır, theirs ise canlı veritabanının şu anki durumudur. Hedef canlı veritabanı olduğundan beklenen canlı anlık görüntü theirs değeridir; yazılacak işlemler ise canlıda henüz bulunmayanlardır (bkz. İşlemleri seçme).

PHP
use Merql\Connection;
use Merql\Merql;
use Merql\Plan\OperationSelection;
use Merql\Plan\SelectedMergeResultFactory;
use Merql\Snapshot\SnapshotStore;

Merql::init(Connection::sqlite('/data/live.sqlite'));

$plan = Merql::plan('promote-1', 'base', 'ours', 'theirs');

// Skip rows with unresolved conflicts.
$conflicted = [];
foreach ($plan->conflicts as $conflict) {
    $conflicted[$conflict->table . "\0" . $conflict->rowKey] = true;
}

$ids = [];
foreach ($plan->operations as $operation) {
    $missing = $operation->source === 'ours'
        || ($operation->source === 'merged' && $operation->type === 'update');

    if ($missing && !isset($conflicted[$operation->table . "\0" . $operation->rowKey])) {
        $ids[] = $operation->id;
    }
}

$selected = (new SelectedMergeResultFactory())->fromOperationSelection(
    $plan,
    OperationSelection::fromIds($ids),
    SnapshotStore::load('base'),
);

$applied = Merql::applyGuarded($selected, SnapshotStore::load('theirs'));

if ($applied->hasErrors()) {
    foreach ($applied->errors() as $error) {
        echo $error . "\n";
    }
}

Merql::applyGuarded(), Merql::init() öğesine iletilen veritabanına yazar. Beklenen canlı anlık görüntü aynı veritabanını açıklamalıdır: hedef veritabanından alın ve önkoşulların anlamlı olması için yeterince yakın zamanda oluşturun.

Önkoşullar

Korumalı SQL, oluşturulan ifadelere canlı satır önkoşulları ekler:

  • güncellemeler, hedef satır kimliğinin var olmasını ve kimlik dışı sütun değerlerinin beklenen canlı satırla eşleşmesini gerektirir,
  • silmeler, hedef satır kimliğinin var olmasını ve kimlik dışı sütun değerlerinin beklenen canlı satırla eşleşmesini gerektirir,
  • eklemeler, hedef kimliğin henüz var olmamasını gerektirir.

Herhangi bir ifade sıfır satırı etkilerse merql planı eski kabul eder. İşlem geri alınır ve döndürülen ApplyResult, Optimistic precondition failed for guarded merge statement. hatasını içerir

MySQL üzerinde, değerleri canlı satırla zaten eşleşen bir güncelleme de sıfır satırı etkiler; çünkü MySQL, eşleşen satırları değil değişen satırları sayar. Dolayısıyla satır eşleşse bile güncelleme eski olarak başarısız olur (#2). SQLite eşleşen satırları sayar ve bunu kabul eder. Bu, her iki tarafın da bir satırda aynı değişikliği yaptığı merged güncellemesinde görülebilir.

İşlemleri seçme

Birleştirme sonucu, tabanı birleştirilmiş duruma dönüştürdüğü için her iki tarafın işlemlerini içerir. Zaten theirs durumunu tutan bir hedefe uygulandığında, theirs tarafından gelen işlemler hedefin zaten sahip olduğu değişiklikleri tanımlar ve bu işlemlerin önkoşulları başarısız olur:

İşlem theirs durumunu tutan hedefteki durum Seç
ours ekleme, güncelleme veya silme Eksik Evet
merged güncelleme (iki taraf da satırı değiştirdi) theirs sütunları var, ours sütunları eksik Evet
theirs ekleme Satır var; korumalı ekleme bu yüzden sıfır satırı etkiler Hayır
merged silme (iki taraf da satırı sildi) Satır yok; korumalı silme bu yüzden sıfır satırı etkiler Hayır
theirs güncelleme veya silme Zaten uygulandı Hayır

Merql::merge() öğesinin tüm sonucunu applyGuarded() öğesine iletmek, theirs bir satır eklediğinde veya iki taraf da bir satırı sildiğinde başarısız olur. Önce yukarıdaki gibi kaynağa göre veya bir inceleme UI öğesinden oluşturulan ChangeGroupSelection ile işlemleri seçin. $plan->conflicts içinde listelenen satırları dışarıda bırakın: seçili sonuç her zaman temizdir ve çakışan bir satıra ait işlem, çakışan sütunda ours değerini taşır (bkz. Birleştirme Planları).

Seçili Uygulama

Korumalı uygulama, değişiklik grubuna göre yapılan seçimler de dahil olmak üzere birleştirme planından üretilen seçili birleştirme sonuçlarıyla çalışır.

PHP
use Merql\Plan\ChangeGroupSelection;
use Merql\Plan\SelectedMergeResultFactory;
use Merql\Snapshot\SnapshotStore;

$selection = ChangeGroupSelection::fromIds([$plan->changeGroups[0]->id]);
$selected = (new SelectedMergeResultFactory())->fromChangeGroupSelection(
    $plan,
    $selection,
    SnapshotStore::load($plan->baseSnapshot),
);

$applied = Merql::applyGuarded($selected, SnapshotStore::load($plan->theirsSnapshot));

Bu, bir ana uygulamanın incelenmiş grupların bir alt kümesini aşamalamasına ve plan oluşturulduktan sonra canlı satırların değişmediğini doğrulamasına olanak tanır.

SQL Önizlemesi

Korumalı ifadeleri yürütmeden incelemek için SqlGenerator::generateGuarded() kullanın.

PHP
use Merql\Apply\SqlGenerator;
use Merql\Snapshot\SnapshotStore;

$statements = SqlGenerator::generateGuarded(
    $selected,
    SnapshotStore::load($plan->theirsSnapshot),
);

foreach ($statements as $statement) {
    echo $statement['sql'] . "\n";
}

Oluşturulan ifadeler yine parametrelidir. Önkoşullar, güncelleme ve silmeler için ek WHERE koşullarıyla, eklemeler içinse NOT EXISTS denetimleriyle belirtilir.

Korumalı veya normal uygulama

Merql::apply(), aynı işlemleri önkoşullar olmadan yürütür. Böylece canlı satır plan oluşturulduğundan beri değişmiş olsun ya da olmasın güncellemeler ve silmeler başarılı olur; mevcut bir satırı ekleme girişimi ise veritabanının yinelenen anahtar hatasıyla başarısız olur. Hedefin hâlâ tabanı tuttuğunu bildiğinizde normal uygulamayı, anlık görüntüsü alındıktan sonra hedefe başka yazma işlemleri yapılmış olabileceğinde korumalı uygulamayı kullanın.