Nasıl bu işlem zaten başlatılmış tespit ediyorsunuz?

6 Cevap php

I am using Zend_Db to insert some data inside a transaction. My function starts a transaction and then calls another method that also attempts to start a transaction and of course fails(I am using MySQL5). So, the question is - how do I detect that transaction has already been started? Here is a sample bit of code:

       try {
                    Zend_Registry::get('database')->beginTransaction();

                    $totals = self::calculateTotals($Cart);
                    $PaymentInstrument = new PaymentInstrument;
                    $PaymentInstrument->create();
                    $PaymentInstrument->validate();
                    $PaymentInstrument->save();

                    Zend_Registry::get('database')->commit();
                    return true;

            } catch(Zend_Exception $e) {
                    Bootstrap::$Log->err($e->getMessage());
                    Zend_Registry::get('database')->rollBack();
                    return false;
            }

PaymentInstrument içeride :: o işlem zaten başlatılmış diyor istisna oluşturan başka beginTransaction deyim vardır oluşturmak.

6 Cevap

Çerçeve bir hareket başlatmış olmadığını bilmenin bir yolu vardır. Hatta framework bunu yürütmek SQL deyimleri ayrıştırmak değil, çünkü yaklaşık bilemem $db->query('START TRANSACTION') hangi kullanabilirsiniz.

Nokta, bir işlem başlatılmış veya yok ettik olmadığını izlemek için bir uygulama sorumluluğu olmasıdır. Bu çerçeve yapabileceği bir şey değil.

Bazı çerçeveler bunu deneyin biliyorum ve size kez eşleşen dizi taahhüt veya geri alma yaptık yalnızca onu çözmek, bir işlem başladık kaç kez saymak gibi cockamamie şeyler. Ama bu taahhüt veya geri alma aslında bunu yapacak eğer fonksiyonların hiçbiri biliyorum çünkü tamamen sahte olduğunu, ya da iç içe başka bir katman iseniz.

(Ben bu tartışmanın bir kaç kez yaşadım söyleyebilir misin? :-)

edit: Propel size bunu söylemek taahhüt etmez "iç işlem" kavramını destekleyen bir PHP veritabanı erişimi kütüphanedir. Bir işlem Başlangıçta sadece bir sayacı artırır ve taahhüt / geri alma sayacını azaltır. Aşağıda başarısız bir kaç senaryo tanımlamak bir posta listesi parçacığı bir alıntıdır.


Ya da değil gibi, işlemler "küresel" ve onlar nesne yönelimli kapsüllemeyi uymayanlar.

Problem scenario #1

I commit(), benim yaptığım değişiklikler kararlıyız diyorsun? Ben bir "iç işlem" İçeri giriyorum eğer onlar değildir. Dış işlem yönetir kodu geri almak için seçebilirsiniz, ve benim değişiklikler benim bilgisi ve kontrolü olmadan atılacaktır.

Örneğin:

  1. Model A: işlem başlar
  2. Model A: bazı değişiklikler yürütmek
  3. Model B: işlem başlatmak (sessiz no-op)
  4. Model B: bazı değişiklikler yürütmek
  5. Model B: işlemek (sessiz no-op)
  6. Model A: rollback (atar model A değişiklikler ve model B değişikliklerin)
  7. Model B: WTF!? Ne benim değişiklikler oldu?

Problem scenario #2

Bir iç işlem geri alır, bir dış hareket tarafından yapılan meşru değişiklikleri atmak olabilir. Kontrol dış koduna döndüğünde, onun işlem hala etkin ve kararlı olması için mevcut olduğuna inanmaktadır. Lütfen yama ile, commit() diyebiliriz ve transDepth şimdi 0 olduğundan, sessizce $transDepth -1 açardı ve bir şey işlemekle sonra değil, doğru dönün.

Problem scenario #3

I commit() veya rollback() Etkin herhangi bir işlem olduğunda ararsanız, o $transDepth -1 ayarlar. Sonraki beginTransaction() işlem geri alınır, ne de taahhüt edilebilir ne demektir, 0 seviyesini artırır. Sonraki çağrılar commit() sadece -1 veya daha fazla için işlem azaltacaktır ve başka gereksiz beginTransaction() yeniden seviyesini arttırmak için ne kadar taahhüt muktedir asla.

Temelde, veritabanı muhasebe yapmak için izin vermeden uygulama mantığı işlemleri yönetmek için çalışırken bir mahkum fikirdir. Eğer bir uygulama isteği belirtik işlem denetimi kullanmak için iki model için bir gereklilik varsa, o zaman iki DB bağlantıları, her model için bir açmalısınız. Sonra her modeli işlenen veya birbirinden bağımsız olarak geri alınabilir kendi aktif işlem, olabilir.

(http://www.nabble.com/Zend-Framework-Db-Table-ORM-td19691776.html bakınız)

Bir try / catch yapın: istisna işlem zaten (ne olursa olsun, hata kodu veya dize mesaj dayalı) başladığını ise, devam. Aksi takdirde, yine istisna.

Zend_Registry in BeginTransaction () dönüş değerini saklamak ve daha sonra kontrol ediniz.

Zend_Db'nin yanı sıra adaptörleri (hem mysqli ve PDO versiyonları) baktığımızda gerçekten işlem durumunu kontrol etmek için güzel bir yol göremiyorum. Neyse ki yakında çıkıp planlanan bir yama ile - Bu konuyla ilgili bir ZF issue var gibi görünüyor.

Bunun yerine gayri resmi ZF kodu çalıştırmak istiyorum eğer, şu an için, mysqli documentation Eğer err. (bir işlem şu anda iseniz SELECT @@autocommit bulmak için diyor .. değil autocommit modunda).

Ben 5.1 (ama 5,0) çalışan bir MySQL saklanan işleve sahip olduğu can tell you if you're in a transaction or not. Yukarıdan, ancak MySQL içinde Esasen try / catch öneri. Hala 5.0 için işe alma konusunda çalışıyoruz.

Web bakan PHP, komut hemen hemen her zaman tek bir web isteğiyle sırasında çağrılır. Ne gerçekten bu durumda yapmak istiyorum bir hareketi başlatmak ve komut bitmeden doğru taahhüt olduğunu. Bir şey yanlış giderse, bir özel durum ve tüm şey geri dönebilirsiniz. Bu gibi:

wrapper.php:

try {
   // start transaction
   include("your_script.php");
   // commit transaction
} catch (RollbackException $e) {
   // roll back transaction
}

Durum birkaç bağlantıları açılması olabilir Sharding, biraz daha karmaşık alır. Sen işlemler yazısının sonunda işlenen veya geri alınması gereken bağlantıları bunları bir listeye eklemek zorunda. Ancak, işlemlerin küresel bir muteksi yoksa taahhütte yaparken Sharding durumunda, başka bir komut dosyası kırıkların onların işlemlerini taahhüdünde olabilir çünkü gerçek izolasyon veya eşzamanlı işlemler atomicity ulaşmak kolayca mümkün olmayacaktır fark senin. Ancak, MySQL distributed transactions kontrol etmek isteyebilirsiniz.