DatabaseError: geçerli işlem iptal edildi, işlem bloğu sonuna kadar komutlar yok sayıldı mı?


252

İletide birçok hata var:

"DatabaseError: current transaction is aborted, commands ignored until end of transaction block"

sonra Django projesinin veritabanı motoru olarak python-psycopg'den python-psycopg2'ye değiştirildi.

Kod aynı kalır, sadece bu hataların nereden geldiğini bilmiyorum.


2
Bu soruna son çözümünüzün ne olduğunu merak ediyorum? Aynı sorunu yaşıyorum, ancak barındırma sağlayıcım sorgu hataları günlüğe kaydetmediği için şimdiye kadar neyin yanlış gittiğini anlamak imkansızdı.
gerdemb

2
Sonunda önbellek arka ucu olarak bir veritabanı tablosu kullanırken benim sorun bir hata aşağı izledi. Django bug: code.djangoproject.com/ticket/11569 StackOverflow tartışma: stackoverflow.com/questions/1189541/…
gerdemb

7
FYI Sadece django olmadan psycopg2 kullanıyorsanız, conn.rollback()(conn sizin bağlantı nesnenizdir) hatayı temizler, böylece diğer sorguları çalıştırabilirsiniz
User

Yanıtlar:


177

Bir sorgu hata ürettiğinde ve ilk önce işlemi geri almadan başka bir sorgu çalıştırmayı denediğinizde postgres bunu yapar. (Verilerinizi bozmanızı önlemek için bunu bir güvenlik özelliği olarak düşünebilirsiniz.)

Bunu düzeltmek için, kötü sorgunun kodda nerede yürütüldüğünü bulmak istersiniz. Postgresql sunucunuzdaki log_statement ve log_min_error_statement seçeneklerini kullanmak yararlı olabilir .


sorun python-psycopg kullanırken, böyle bir hata ortaya çıktı. psycopg2 postgres ile konuşan farklı bir mekanizma uyguladı mı?
jack

4
Sunucuyla konuşma yöntemi büyük olasılıkla önemli değildir, ancak daha önce kullandığınız sürümün, yeni sürüm önemli değilken, bir şekilde varsayılan otomatik moda geçmesi mümkündür. Hata hala oluşmuş olabilir, ancak daha kolay kaçırmış olabilirsiniz. Eski sürümden bu yana veri türü dönüşümünün veya başka bir şeyin değişmiş olması da mümkündür. Ne olursa olsun, en iyi düzeltme, sorunun ne olduğunu görebilmeniz için kötü sorguyu izlemektir.
ɈsәɹoɈ

133

Hatadan kurtulmak için kodunuzu düzelttikten sonra son (hatalı) işlemi geri alın:

from django.db import transaction
transaction.rollback()

Hatanın oluşmasını önlemek için try-haric komutunu kullanabilirsiniz:

from django.db import transaction, DatabaseError
try:
    a.save()
except DatabaseError:
    transaction.rollback()

Bakınız: Django belgeleri


3
Bu, temel sorunu giderir ve iptal edilen işleme neden olan bir ifadeden sonra kurtarmanıza izin verir.
RichVel

bunu deneyin / hariç.
tomwolber

3
Neden IntegrityErrortemel sınıfı kullanmıyorsunuz DatabaseError?
Jonathan

Herhangi bir nedenle geri alma işlemini "hariç" bölümünün dışına taşımak zorunda kaldım. Ben .save () değil .bulk_create () kullanıyordum
nu everest

Bu izledikten sonra Django 1.4.16 ile çalıştı stackoverflow.com/a/15753000/573034
Paolo

50

Ben de aynı sorunla karşılaştım. Burada yaşıyorum sorun benim veritabanı düzgün senkronize değildi oldu. Basit sorunlar her zaman en öfkeye neden gibi görünüyor ...

Django db'nizi uygulama dizininizden terminal içine senkronize etmek için şunu yazın:

$ python manage.py syncdb

Düzenleme: Django-south kullanıyorsanız, '$ python manage.py migrate' komutunu çalıştırmanın da bu sorunu çözebileceğini unutmayın.

Mutlu kodlama!


3
Açık olanı belirtmek için seçildi. Ben olsa birden fazla oy vermek olmaz çünkü büyük olasılıkla aranan cevap değildi.
Jameson Quinn

5
Benzer bir şekilde python manage.py migrate <app>... tüm uygulamalarım için düzelttim .
Clayton

3
@Clayton - söylemiyorsunuz, ama kullandığınızı varsayıyorum django-south - migratekomut django'da yerleşik değil.
Greg Ball

@ GregBall- Bu doğru ... Ben django-south kullanıyorum. Belirtmediğim için üzgünüm.
Clayton

Syncdb yaparken bu hatayı alıyorum - django tabloları geçer sipariş ile ilgili olduğunu düşünüyorum.
Stuart Axon


34

Deneyimlerime göre, bu hatalar şu şekilde olur:

try:
    code_that_executes_bad_query()
    # transaction on DB is now bad
except:
    pass

# transaction on db is still bad
code_that_executes_working_query() # raises transaction error

İkinci sorguda yanlış bir şey yoktur, ancak gerçek hata yakalandığından, ikinci sorgu (çok daha az bilgilendirici) hatayı yükseltir.

edit: Bu sadece exceptyan tümceyi yakalarsa IntegrityError(veya başka bir düşük düzey veritabanı istisnası), DoesNotExistbu hata gibi bir şey yakalarsanız , gelmez çünkü olurDoesNotExist bozmaz.

Burada ders denemek / hariç / geçmek yok.


16

Ben desen priestc bahsettiğim PostgreSQL kullanırken bu sorunun olağan nedeni olması daha muhtemel olduğunu düşünüyorum.

Ancak kalıp için geçerli kullanımlar olduğunu hissediyorum ve bu sorunun her zaman bundan kaçınmak için bir neden olması gerektiğini düşünmüyorum. Örneğin:

try:
    profile = user.get_profile()
except ObjectDoesNotExist:
    profile = make_default_profile_for_user(user)

do_something_with_profile(profile)

Bu kalıpla iyi hissediyorsanız, ancak her yerde açık işlem işleme kodundan kaçınmak istiyorsanız, otomatik taahhüt modunu (PostgreSQL 8.2+) etkinleştirmek isteyebilirsiniz: https://docs.djangoproject.com/en/ dev / ref / veritabanları / # autocommit mod

DATABASES['default'] = {
    #.. you usual options...
    'OPTIONS': {
        'autocommit': True,
    }
}

Önemli performans değerlendirmeleri (veya başka bir tür) olup olmadığından emin değilim.


6

Bunu etkileşimli kabuktayken alırsanız ve hızlı bir düzeltmeye ihtiyacınız varsa, bunu yapın:

from django.db import connection
connection._rollback()

aslen bu cevapta görülüyor


6

postgresTerminalde hatalı bir işlem çalıştırırken benzer bir davranışla karşılaştım . Olarak Hiçbir şey, bundan sonra geçti databasebir durumdadır error. Ancak, hızlı bir düzeltme olarak, kaçınmayı göze alabilirseniz rollback transaction. Benim için hile yaptı:

COMMIT;


Ben bir cevap vardı, tam olarak aradığım cevap budur.
sarink

5

Silimar sorunum var. Çözüm db'yi ( manage.py syncdbya manage.py schemamigration --auto <table name>da güneyi kullanıyorsanız) taşımaktı .


5

sadece geri almayı kullan

Örnek kod

try:
    cur.execute("CREATE TABLE IF NOT EXISTS test2 (id serial, qa text);")
except:
    cur.execute("rollback")
    cur.execute("CREATE TABLE IF NOT EXISTS test2 (id serial, qa text);")

1

Sadece bu hatayı da aldım ama kodun 100 karakterlik bir sütunda 125 karakterlik bir dize saklamaya çalıştığı başka bir daha ilgili hata mesajını maskeliyordum:

DatabaseError: value too long for type character varying(100)

Yukarıdaki mesajın görünmesi için kod aracılığıyla hata ayıklamak zorunda kaldım, aksi takdirde görüntülenir

DatabaseError: current transaction is aborted

1

@Priestc ve @Sebastian'a yanıt olarak, böyle bir şey yaparsanız ne olur?

try:
    conn.commit()
except:
    pass

cursor.execute( sql )
try: 
    return cursor.fetchall()
except: 
    conn.commit()
    return None

Ben sadece bu kodu denedim ve herhangi bir olası hatalar umurumda olmadan sessizce başarısız çalışıyor ve sorgu iyi olduğunda çalışıyor gibi görünüyor.


1

@ AnujGupta'nın cevabının doğru olduğuna inanıyorum. Ancak geri alma, yakalamanız ve işlemeniz gereken bir istisna oluşturabilir:

from django.db import transaction, DatabaseError
try:
    a.save()
except DatabaseError:
    try:
        transaction.rollback()
    except transaction.TransactionManagementError:
        # Log or handle otherwise

Bu kodu çeşitli save()konumlarda yeniden yazdığınızı fark ederseniz , yöntem ayıklayabilirsiniz:

import traceback
def try_rolling_back():
    try:
        transaction.rollback()
        log.warning('rolled back')  # example handling
    except transaction.TransactionManagementError:
        log.exception(traceback.format_exc())  # example handling

Son olarak, aşağıdakileri kullanan yöntemleri koruyan bir dekoratör kullanarak öngörebilirsiniz save():

from functools import wraps
def try_rolling_back_on_exception(fn):
    @wraps(fn)
    def wrapped(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except:
            traceback.print_exc()
            try_rolling_back()
    return wrapped

@try_rolling_back_on_exception
def some_saving_method():
    # ...
    model.save()
    # ...

Yukarıdaki dekoratörü uygulasanız bile, try_rolling_back()özel işlemin gerekli olduğu ve jenerik dekoratör işlemesinin yeterli olmadığı durumlarda manuel olarak kullanmanız gerektiğinde çıkarılan bir yöntem olarak tutmak hala uygundur .


1

Bu benim için çok garip bir davranış. Kimsenin kurtarış noktaları düşünmediğine şaşırdım. Kodumda başarısız sorgu beklenen davranış oldu:

from django.db import transaction
@transaction.commit_on_success
def update():
    skipped = 0
    for old_model in OldModel.objects.all():
        try:
            Model.objects.create(
                group_id=old_model.group_uuid,
                file_id=old_model.file_uuid,
            )
        except IntegrityError:
            skipped += 1
    return skipped

Savepoints kullanmak için bu şekilde kod değiştirdim:

from django.db import transaction
@transaction.commit_on_success
def update():
    skipped = 0
    sid = transaction.savepoint()
    for old_model in OldModel.objects.all():
        try:
            Model.objects.create(
                group_id=old_model.group_uuid,
                file_id=old_model.file_uuid,
            )
        except IntegrityError:
            skipped += 1
            transaction.savepoint_rollback(sid)
        else:
            transaction.savepoint_commit(sid)
    return skipped

1

Flask kabuğunda, tek yapmam gereken bunu aşmaktı session.rollback().


1

Bu sorunla karşılaştım, hata işlemleri doğru bir şekilde sona ermediğinden hata çıkıyor postgresql_transactions, İşlem Denetimi komutunu burada buldum

İşlem Kontrolü

İşlemleri kontrol etmek için aşağıdaki komutlar kullanılır

BEGIN TRANSACTION  To start a transaction.

COMMIT  To save the changes, alternatively you can use END TRANSACTION command.

ROLLBACK  To rollback the changes.

Bu yüzden END TRANSACTIONhatayı TRANSACTION, kodu böyle bitirmek için kullanın :

    for key_of_attribute, command in sql_command.items():
        cursor = connection.cursor()
        g_logger.info("execute command :%s" % (command))
        try:
            cursor.execute(command)
            rows = cursor.fetchall()
            g_logger.info("the command:%s result is :%s" % (command, rows))
            result_list[key_of_attribute] = rows
            g_logger.info("result_list is :%s" % (result_list))
        except Exception as e:
            cursor.execute('END TRANSACTION;')
            g_logger.info("error command :%s and error is :%s" % (command, e))
    return result_list

-6

"set_isolation_level (0)" üzerinden işlemi devre dışı bırakabilirsiniz

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.