veritabanı kısıtlamaları zorlanarak: sql vs kodu

5 Cevap php

Bu this question kadar izleyin.

İşte benim şema

CREATE TABLE A(
     id serial NOT NULL,
     date timestamp without time zone,
     type text,
     sub_type text,
     filename text,
     filepath text,
     filesize integer,
     lock_status int
 );

Bu veritabanı, kullanıcı tipi, alt tipi, dosya adı, dosya yolunu, dosya boyutu gibi uzun 'lock_status not set' olarak güncelleyebilirsiniz.

Yani, web sayfası kod (php) Ben öğeyi güncellemeden önce lock_status kontrol edebilirsiniz.

Ancak, başka bir kullanıcı ilk kullanıcının kontrol ve arasındaki zaman içinde kilit durumunu güncelledi bir durum söz konusu olabilir güncelleyin.

Yani, satır güncellenir önce kilit durumunu kontrol etmek için SQL bir yolu var mı?

  • web sayfası kod php olduğunu
  • veritabanı PostgreSQL

edit Yukarıdaki düzenlenebilir alan listesine tipi, alt tipi eklendi

5 Cevap

Tabii, kullanmak UPDATE ... WHERE lock_status = 0. Alternatif olarak, stored procedures kullanarak deneyebilirsiniz.

Temiz yolu, Bay Patates Kafa dediği gibi, o atom olması garanti olan bir tek bir SQL deyimi, Çünkü sadece. Sadece lock_status = 0 satır etkileyecek bir WHERE yan tümcesi kullanmaktır. Herhangi bir satır (örneğin, @ @ Rowcount kullanarak) etkilenen ve süresiz tekrar deneyerek ya da bir hata mesajı, vb göstererek ya, buna göre tepki olsaydı, o zaman görebilirsiniz

İki adımda kontrol ve güncelleme ile sorun (örn. "işlemi yürütme ... TRANSACTıON'ı BEGIN") açık bir işlem sarılmasıdır sürece, onlar not atomik olması garanti olan, bu nedenle teorik olarak olması Kilit kapalı ve devam olduğunu düşünüyorum birden fazla işlem olsun. Bu ifadeler yürütülür ki hızı ile, bu aynı zamanda bu şey üzerinde beceriyor kullanıcıların bir ton (bin?) Ile bir derece eşzamanlı ortam var olmadıkça hiç ne olur inanılmaz düşüktür çünkü "teorik" demek. İşte bu gibi hataları sık sık farkedilmeden gitmek neden, ama daha sonra garip açıklanamayan hata çıkabilirler.

Sorunu bu tür hakkında daha fazla bilgi edinmek için, bu gibi eşzamanlı programlama bir kitap okumak isteyebilirsiniz: Concurrent Programming by Gregory Andrews.

Sen satır düzeyinde kilitleme içine bakmak isteyebilirsiniz. Postgres o var gibi görünüyor.

Bir tetikleyici ve PL / pgsql fonksiyonu ile veritabanı tarafında sadece tek bir örnek prosedür:

CREATE OR REPLACE FUNCTION trgfn_ensure_unlocked() RETURNS TRIGGER AS $trig$
  DECLARE
  BEGIN
    IF (OLD.lock_status <> 0) THEN
      RAISE EXCEPTION 'Row is locked';
    END IF;
    RETURN NEW;
  END;
$trig$ LANGUAGE plpgsql;

CREATE TRIGGER trg_check_unlocked BEFORE UPDATE ON table_name
      FOR EACH ROW EXECUTE PROCEDURE trgfn_ensure_unlocked();

Temel olarak, satır sürümü (güncellemeden önce) eski o kontrol edecek bir plpgsql fonksiyonu, lock_status 0'dır. Bir istisna olmayacaktır eğer.

Bu işlev, bu tabloda bir SQL UPDATE yaparken otomatik olarak çağrılacak tetikleyici tarafından denir.

Bu yardımcı olur umarım ...

Ben kontrol ve aynı zamanda lock_status biraz ayarını öneriyoruz.

Bir UPDATE A SET lock_status = 1 WHERE id = ... AND lock_status = 0 Sorun. Bu sorgu için bir açık işlem gerek kalmadan atom olduğunu. Bu kilit uygulanabilir değil güncelleme 1 nesne sayısını dönmezse. Sonra sadece birincil anahtar hala var olduğunu onaylamanız gerekir. Eğer birden fazla yerden ve / veya birden fazla tablo üzerinde çağırarak olacak eğer bir saklı yordam için bu hareket düşünebilirsiniz.

pseudo-PHP:

$result = pg_query_params($conn, "UPDATE A SET lock_status = 1 WHERE id = $1 AND lock_status = 0", $id);
$tuples = pg_affected_rows($result);

if ($tuples < 1) {
    // couldn't lock
} else {
    // lock applied
}