修正ステートメントがあるとします。
cursor = conn.cursor()
# some code
affected_rows1 = cursor.execute(update_statement1, params1)
# some code
conn.commit()
cursor.close()
コードのブロックをtry ... except
でラップし、例外が発生したときにトランザクションを明示的にロールバックする必要がありますか?また、ロールバックするためにどのMySQLdb例外をキャッチする必要がありますか?以前はStandardError
この場合、しかし今、私はコードのブロックが明示的なロールバックさえ必要とするだろうということをためらっています。
次の例は少し難しいですが、最初の更新ステートメントが成功した場合は、明示的なロールバックが必要であることを理解しています。それでも、この場合、どの例外をキャッチする必要がありますか?
cursor = conn.cursor()
# some code
affected_rows1 = cursor.execute(update_statement1, params1)
# some code
affected_rows2 = cursor.execute(update_statement2, params2)
#some code
conn.commit()
cursor.close()
このリンク は、キャッチできるさまざまなタイプのエラーを示しています。 MySQLdb.Error
は、他のすべてのMySQLエラーの派生元となる標準の基本クラスです。
MySQLdb自体に関連するエラーに集中できるため、通常はMySQLdb.Error
を使用します。対照的に、StandardError
はほとんどすべての例外をキャッチします(より良いデバッグ機能が必要な場合は必要ありません)。さらに、MySQLdb.Error
を使用すると、正確なエラーメッセージ(MySQLエラー番号など)を表示できるため、デバッグを高速化できます。
質問の最初の部分に来ると、データベースステートメントの場合、エラーの場合にトランザクションをロールバックする必要があります(サポートされている場合)。
私が従う方法は、各execute
ステートメントをtryexcept句でラップし(MySQLdb.Error
をキャッチ)、エラーが発生した場合はエラーメッセージを出力して終了する前にロールバックを使用することです。
ただし、落とし穴があります。 MySQLdbでは、DBに加えた変更は、明示的にcommitを呼び出すまで、実際にはデータベースに書き込まれません。したがって、論理的には、ロールバックは必要ありません。
例として、
conn = MySQLdb.connection(db=, Host=, passwd=, user=)
cur = conn.cursor()
#Say you have a table X with one entry id = 1 and total = 50
cur.execute("update X set total = 70 where id = 1")
#Actual DB has not yet changed
cur.execute("update X set total = 80 where id = 1")
#Actual DB has still not changed
コミットせずにプログラムを終了した場合、commit()を呼び出したことがないため、DBの値は50のままです。
これはあなたが理想的にそれをする方法です:
conn = MySQLdb.connection(db=, Host=, passwd=, user=)
cur = conn.cursor()
#Say you have a table X with one entry id = 1 and total = 50
try:
cur.execute("update X set total = 70 where id = 1")
except MySQLdb.Error,e:
print e[0], e[1]
conn.rollback()
cur.close()
conn.close()
#print lengthy error description!!
sys.exit(2)
#Note: Value in table is still 50
#If you do conn.commit() here, value becomes 70 in table too!!
try:
cur.execute("update X set total = 80 where id = 1")
except MySQLdb.Error,e:
print e[0], e[1]
conn.rollback()
cur.close()
conn.close()
#print lengthy error description!!
sys.exit(2)
#Value in DB will be
#a) 50 if you didn't commit anywhere
#b) 70 if you committed after first execute statement
conn.commit()
#Now value in DB is 80!!
cur.close()
conn.close()
私見ですが、同じ接続を引き続き使用する場合は、トランザクションをロールバックする必要があります。それ以外の場合は、トランザクションの終了時にエラーがコミットされる前のすべてがコミットされます。キャッチする例外として、私は常にMySQLdb.Error
を使用しますが、それが正しいかどうかはわかりません。