私はビュー機能を持っています:
@transaction.commit_manually
def xyz(request):
if ABC:
success = something()
if success:
status = "success"
transaction.commit()
else:
status = "dataerrors"
transaction.rollback()
else:
status = "uploadproblem"
transaction.rollback()
return render(request, "template.html", {
'status': status,
})
すべてのコードパスが何らかの方法でトランザクションを終了すると思います。しかし、Djangoはそうではないと不平を言っているようです。何かアイデアはありますか?
Django Version: 1.3
Exception Type: TransactionManagementError
Exception Value: Transaction managed block ended with pending COMMIT/ROLLBACK
編集:コードパスを変更するために他の例外はスローされていません。
同様の問題が発生し、それに何時間も費やした後、私はこの状況をデバッグする方法を見つけました。
何らかの理由で、@ transaction.commit_manuallyデコレータは関数で発生する例外を沈黙させます。
関数からデコレータを一時的に削除すると、例外が表示され、修正してデコレータを元に戻します。
私も同じ問題を抱えていました。私が見つけた唯一の解決策は、try/final句を使用して、コミットが確実に行われるようにすることでしたafterレンダリング。
@transaction.commit_manually
def xyz(request):
committed = False
try:
if ABC:
success = something()
if success:
status = "success"
transaction.commit()
committed = True
else:
status = "dataerrors"
transaction.rollback()
committed = True
else:
status = "uploadproblem"
transaction.rollback()
committed = True
return render(request, "template.html", {
'status': status,
})
finally:
if not committed:
transaction.rollback() # or .commit() depending on your error-handling logic
意味がありませんが、私にとってはうまくいきました。
同じ問題が発生し、例外が発生した場合に手動でトランザクションを適切に閉じても、手動トランザクションスコープ内で再度ormに書き込むと、何らかの理由でトランザクションが再開され、トランザクション例外が発生するように見えることを学びました。
with transaction.commit_manually():
try:
<exciting stuff>
transaction.commit()
except Exception, e:
transaction.rollback()
o.error='failed' <== caused transaction exception
この問題が発生する可能性があるもう1つの理由は、システムに複数のデータベースがある場合です。
私はこのエラーを克服することができました
@transaction.commit_manually(using='my_other_db')
def foo():
try:
<db query>
transaction.commit(using='my_other_db')
except:
transaction.rollback(using='my_other_db')
私は同様の問題を抱えていました、多分このコードはあなたのためにうまくいくでしょう:
@transaction.commit_on_success
def xyz(request):
if ABC:
success = something()
if success:
status = "success"
else:
status = "dataerrors"
transaction.rollback()
else:
status = "uploadproblem"
transaction.rollback()
return render(request, "template.html", {
'status': status,
})
他の人が言っているように、decorated関数内で発生する例外は、TransactionManagementError
例外によって上書きされるため、「失われます」。
_transaction.commit_manually
_デコレータを拡張することを提案します。私のデコレータ_transaction_commit_manually
_は内部で_transaction.commit_manually
_デコレータを使用しています。デコレートされた関数で例外が発生した場合、デコレータは例外をキャッチし、transaction.rollback()
を実行して、例外を再度発生させます。したがって、トランザクションは正しくクリアされ、元の例外は失われません。
_def _create_decorator_transaction_commit_manually(using=None):
def deco(f):
def g(*args, **kwargs):
try:
out = f(*args, **kwargs)
except Exception as e:
if using is not None:
transaction.rollback(using=using)
else:
transaction.rollback()
raise e
return out
if using is not None:
return transaction.commit_manually(using=using)(g)
return transaction.commit_manually(g)
return deco
def transaction_commit_manually(*args, **kwargs):
"""
Improved transaction.commit_manually that does not hide exceptions.
If an exception occurs, rollback work and raise exception again
"""
# If 'using' keyword is provided, return a decorator
if 'using' in kwargs:
return _create_decorator_transaction_commit_manually(using=kwargs['using'])
# If 'using' keyword is not provided, act as a decorator:
# first argument is function to be decorated; return modified function
f = args[0]
deco = _create_decorator_transaction_commit_manually()
return deco(f)
_
これは、未処理の例外がコードのどこかで発生した場合に常に発生します。私の場合、何らかの理由で、例外がデバッガーにスローされなかったため、混乱が生じました。
私は同じ問題を抱えていて、さまざまなアプローチを試しました。これが私のために働いたものですが、これがそれを行う正しい方法であるかどうかはわかりません。 returnステートメントを次のように変更します。
with transaction.commit_on_success():
return render(request, "template.html", {
'status': status,
})
Django Pros、これは正しいアプローチですか?
コードをtry/exceptブロックに配置します。exceptブロックでは、transaction.rollbackを実行し、例外オブジェクトをログに記録します。
@transaction.commit_manually
def xyz(xyz):
try:
some_logic
transaction.commit()
except Exception,e:
transaction.rollback()
print str(e)
必要に応じてデータベースのバックアップを取り、テーブルを削除しますROLLBACK_TEST
データベースから。
mysql> DROP TABLE `ROLLBACK_TEST`;