DatabaseError:現在のトランザクションは中止され、コマンドはトランザクションブロックの終わりまで無視されますか?


252

メッセージで多くのエラーが発生しました:

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

Djangoプロジェクトのデータベースエンジンとしてpython-psycopgからpython-psycopg2に変更した後。

コードは同じままですが、これらのエラーの原因がわからないだけです。


2
この問題に対する最終的な解決策は何ですか?私はこれと同じ問題を抱えていますが、私のホスティングプロバイダーはクエリエラーをログに記録しないため、何が問題なのかを把握することはこれまで不可能でした。
gerdemb 2010年

2
ようやく、データベーステーブルをキャッシュバックエンドとして使用するときに、バグまで問題を追跡しました。Djangoのバグ:code.djangoproject.com/ticket/11569 StackOverflowの議論:stackoverflow.com/questions/1189541/...
gerdemb

7
参考:djangoなしでpsycopg2を使用している場合conn.rollback()(connは接続オブジェクトです)はエラーをクリアして、他のクエリを実行できるようにします
User

回答:


177

これは、クエリがエラーを生成し、最初にトランザクションをロールバックせずに別のクエリを実行しようとしたときにpostgresが行うことです。(データの破損を防ぐための安全機能と考えることができます。)

これを修正するには、コードのどこで不正なクエリが実行されているのかを把握する必要があります。postgresqlサーバーでlog_statementおよびlog_min_error_statementオプションを使用すると役立つ場合があります。


問題は、python-psycopgを使用していたときで、そのようなエラーは発生しませんでした。psycopg2はpostgresと通信する別のメカニズムを実装していますか?
ジャック

4
サーバーと通信する方法はおそらく重要ではありませんが、以前に使用したバージョンのデフォルトが何らかの理由で自動コミットモードになり、新しいバージョンではそうではない可能性があります。エラーはまだ発生している可能性がありますが、見落としがちでした。また、データ型の変換などが旧バージョンから変更されている可能性もあります。とにかく、最善の修正は、悪いクエリを追跡して、何が問題なのかを確認できるようにすることです。
ʇsәɹoɈ

133

エラーを取り除くには、コードを修正した後、最後の(誤った)トランザクションをロールバックします。

from django.db import transaction
transaction.rollback()

エラーの発生を防ぐために、try-exceptを使用できます。

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

参照:Djangoドキュメント


3
これにより、コアの問題が解決され、トランザクションの中止を引き起こしたステートメントの後で回復できるようになります。
RichVel

これは、try / excludeと組み合わせて使用​​します。
tomwolber 2013

3
なぜIntegrityError基本クラスではなく使用するのDatabaseErrorですか?
ジョナサン

なんらかの理由で、ロールバックを「except」セクションの外に移動する必要がありました。私は.save()ではなく.bulk_create()を使用していました
nu everest


50

それで、私はこれと同じ問題に遭遇しました。ここで私が抱えていた問題は、データベースが適切に同期されていないことでした。単純な問題は常に最も不安を引き起こすようです...

django dbを同期するには、アプリディレクトリ内、ターミナル内で次のように入力します。

$ python manage.py syncdb

編集:django-southを使用している場合は、「$ python manage.py migrate」コマンドを実行してもこの問題が解決する場合があります。

幸せなコーディング!


3
明白を述べるために賛成。それはおそらく求められた答えではなかったので、私はこれに複数の賛成票を与えません。
Jameson Quinn

5
python manage.py migrate <app>...ですべてのアプリを同様に修正しました。
クレイトン

3
@Clayton-あなたは言わないが、私はあなたが使っていると思いますdjango-south - migrateコマンドはdjangoに組み込まれていません。
グレッグボール

@ GregBall-そうです...私はdjango-southを使用しています。指定しないでごめんなさい。
クレイトン

syncdbを実行するとこのエラーが発生します-djangoがテーブルを通過する順序に関係していると思います。
スチュアート


34

私の経験では、これらのエラーはこのように発生します:

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

2番目のクエリには何の問題もありませんが、実際のエラーがキャッチされたため、2番目のクエリは(はるかに有益ではない)エラーを発生させるクエリです。

編集:これは、except句がキャッチした場合IntegrityError(または他の低レベルのデータベース例外)にのみ発生します。このDoesNotExistエラーのようなものをキャッチした場合、発生しません。DoesNotExist。トランザクションを破損しないません。

ここでのレッスンは、try / except / passを行わないことです。


16

PostgreSQLを使用している場合、priestcが言及するパターンがこの問題の通常の原因である可能性が高いと思います。

ただし、パターンには有効な使用法があると感じています。この問題が常にそれを回避する理由になるとは思いません。例えば:

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

do_something_with_profile(profile)

このパターンに問題はないが、あちこちで明示的なトランザクション処理コードを避けたい場合は、自動コミットモード(PostgreSQL 8.2+)をオンにすることを検討することをお勧めします。https://docs.djangoproject.com/en/ dev / ref / databases /#autocommit-mode

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

パフォーマンスに関する重要な考慮事項(またはその他のタイプ)があるかどうかはわかりません。


6

対話型シェルでこれを取得し、迅速な修正が必要な場合は、次のようにします。

from django.db import connection
connection._rollback()

この回答で最初に見た


6

postgres端末で誤動作したトランザクションを実行しているときに、同様の動作が発生しました。のdatabase状態であるため、この後は何も起こりませんでしたerror。ただし、回避する余裕がある場合は、簡単に修正できますrollback transaction。以下は私のためのトリックをしました:

COMMIT;


私は担当者でした、これはまさに私が探していた答えです。
19:41にサリンク

5

私はシリマーの問題を抱えています。解決策は、dbを移行することでした(manage.py syncdbまたはmanage.py schemamigration --auto <table name>、南を使用する場合)。


5

ロールバックを使用するだけ

コード例

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

私もこのエラーが発生しましたが、コードが100文字の列に125文字の文字列を格納しようとした別のより関連するエラーメッセージをマスキングしていました。

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

上記のメッセージが表示されるようにコードをデバッグする必要がありました。それ以外の場合は表示されます。

DatabaseError: current transaction is aborted

1

@priestcと@Sebastianに応じて、このようなことをするとどうなるでしょうか。

try:
    conn.commit()
except:
    pass

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

私はこのコードを試したところ、コードは機能しているようで、エラーの可能性を気にすることなく静かに失敗し、クエリが適切なときに機能します。


1

@AnujGuptaの答えは正しいと思います。ただし、ロールバック自体がキャッチして処理する必要のある例外を発生させる可能性があります。

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

このコードをさまざまなsave()場所で書き換えている場合は、extract-methodを実行できます。

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

最後に、以下を使用するメソッドを保護するデコレータを使用して、それを偽装できます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()
    # ...

上記のデコレーターを実装したtry_rolling_back()としても、特定の処理が必要で、汎用的なデコレーターの処理では不十分な場合に手動で使用する必要がある場合に備えて、抽出されたメソッドとして保持しておくと便利です。


1

これは私にとって非常に奇妙な行動です。誰もセーブポイントを考えていなかったことに驚いています。私のコードでは、クエリの失敗は予想される動作でした:

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

セーブポイントを使用するようにこの方法でコードを変更しました:

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

フラスコシェルでは、すべて私がいた行うために必要なsession.rollback()これを乗り越えるために。


1

私はこの問題に遭遇しました、エラートランザクションが正しく終了していないためエラーが出ます、ここpostgresql_transactionsにTransaction Controlコマンドが見つかりました

トランザクション制御

次のコマンドは、トランザクションを制御するために使用されます

BEGIN TRANSACTION  To start a transaction.

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

ROLLBACK  To rollback the changes.

だから私END TRANSACTIONはエラーTRANSACTIONを終了するために、次のようなコードを使用します:

    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)"でトランザクションを無効にできます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.