web-dev-qa-db-ja.com

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

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

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

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

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

222
jack

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

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

157
ʇsәɹoɈ

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

from Django.db import transaction
transaction.rollback()

Try-exceptを使用して、エラーの発生を防ぐことができます。

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

参照: Django documentation

128
Anuj Gupta

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

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

$ python manage.py syncdb

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

ハッピーコーディング!

50

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

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を実行しないことです。

30
priestc

Flaskでは、次のように書くだけです。

curs = conn.cursor()
curs.execute("ROLLBACK")
conn.commit()

追伸ここにドキュメントがあります https://www.postgresql.org/docs/9.4/static/sql-rollback.html

17

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,
    }
}

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

16
Sebastian

インタラクティブシェルでこれを取得し、簡単な修正が必要な場合は、次のようにします。

from Django.db import connection
connection._rollback()

元々 この回答

6
tutuDajuju

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

COMMIT;

6
faizanjehangir

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

4
Daniil Ryzhkov

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

サンプルコード

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);")
2
Umer

@priestcと@Sebastianへの応答として、このようなことをしたらどうでしょうか?

try:
    conn.commit()
except:
    pass

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

私はこのコードを試してみましたが、うまくいくようで、エラーを気にせずに静かに失敗し、クエリが良いときに動作します。

1
Nate

私もこのエラーが発生しましたが、コードが125文字の文字列を100文字の列に保存しようとした、より関連性の高い別のエラーメッセージをマスクしていました。

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

上記のメッセージを表示するには、コードをデバッグする必要がありました。

DatabaseError: current transaction is aborted
1
Thierry Lam

Flask Shellでは、これをすり抜けるにはsession.rollback()が必要でした。

1
watsonic

@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
Jonathan

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

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
homm

この問題に遭遇しました。エラートランザクションが正しく終了していないため、エラーが発生しました。トランザクション制御コマンドのpostgresql_transactionsが見つかりました here

トランザクション制御

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

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
0
Dean Fang