2012-03-21 33 views
12

Giả sử, tôi có một tuyên bố sửa đổi:Python-mysql: khi rollback một cách rõ ràng giao dịch

cursor = conn.cursor() 
# some code 
affected_rows1 = cursor.execute(update_statement1, params1) 
# some code 
conn.commit() 
cursor.close() 

Tôi có nên quấn khối mã với một try ... except và rõ ràng rollback một giao dịch khi một ngoại lệ được nâng lên, và những ngoại lệ MySQLdb nào tôi nên bắt gặp để quay lại? Tôi từng nắm bắt bất kỳ StandardError trong trường hợp này, nhưng bây giờ tôi có một do dự rằng khối mã thậm chí sẽ cần một rollback rõ ràng ở tất cả.

Ví dụ sau hơi khó hơn một chút và tôi hiểu rằng nó yêu cầu khôi phục rõ ràng nếu tuyên bố cập nhật đầu tiên thành công. Tuy nhiên, trong đó trường hợp ngoại lệ tôi nên bắt trong trường hợp này:

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() 

Trả lời

1

IMHO, bạn nên rollback giao dịch nếu bạn tiếp tục sử dụng cùng một kết nối. Khác tất cả mọi thứ trước khi lỗi sẽ nhận được cam kết khi bạn hoàn thành các giao dịch. Đối với ngoại lệ để bắt, tôi luôn sử dụng MySQLdb.Error nhưng tôi không chắc đó là chính xác.

+0

tôi sử dụng thậm chí 'StandardError', và bây giờ đang cố gắng để hiểu những gì là chính xác để đảm bảo. – newtover

-1

Được khuyên nên bọc thực thi() trong một phụ. Đây là cách tôi làm điều đó.

def executeSQL(self, stmt): 
    cursor = self.dbHand.cursor() 

    if not stmt.endswith(";"): 
     stmt += ';' 

    try: 
     cursor.execute(stmt) 
    except MySQLdb.Error, e: 
     self.logger.error("Caught MYSQL exception :%s: while executing stmt :%s:.\n"%(e,stmt)) 
     return False 
+1

Tôi hiểu rằng, câu hỏi của tôi là mặc dù về điều kiện khi gọi ngụ ý 'rollback' – newtover

+1

Bạn có thể làm rõ lợi ích của phương pháp này không? – Dikei

+0

Như @Dikei đã đề cập rollback() nếu ngoại lệ MySQLdb.Error bị bắt. – tuxuday

12

This link hiển thị các loại lỗi khác nhau mà bạn có thể nắm bắt. MySQLdb.Error là lớp cơ sở tiêu chuẩn mà từ đó tất cả các lỗi MySQL khác có nguồn gốc.

Tôi thường sử dụng MySQLdb.Error vì nó cho phép bạn tập trung vào các lỗi liên quan đến MySQLdb. Ngược lại, StandardError sẽ bắt hầu như tất cả các ngoại lệ (không phải thứ bạn muốn nếu bạn muốn có khả năng gỡ lỗi tốt hơn). Ngoài việc sử dụng MySQLdb.Error cho phép bạn hiển thị thông báo lỗi chính xác (số lỗi MySQL và tất cả) để bạn có thể gỡ lỗi nhanh hơn.

Đến phần đầu tiên của câu hỏi, trong trường hợp các câu lệnh cơ sở dữ liệu, thường là cần thiết cho các giao dịch rollback (nếu chúng được hỗ trợ) trong trường hợp có lỗi.

Phương pháp mà tôi theo dõi là bọc mỗi câu lệnh execute trong mệnh đề thử ngoại trừ (bắt MySQLdb.Error) và sử dụng khôi phục nếu có lỗi trước khi in thông báo lỗi và thoát.

Tuy nhiên, có sự bắt giữ. Trong MySQLdb những thay đổi mà bạn thực hiện đối với DB là không phải thực sự được ghi vào cơ sở dữ liệu cho đến khi bạn thực hiện cam kết cuộc gọi. Vì vậy, hợp lý, rollback là không cần thiết.

Như một ví dụ,

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 

Nếu bạn thoát khỏi chương trình mà không cần commiting, giá trị trong DB sẽ vẫn là 50 vì bạn không bao giờ được gọi là cam kết().

Đây là cách bạn lý tưởng sẽ làm điều đó:

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() 
+0

Một mô hình StackOverflow câu trả lời (giải thích + ví dụ làm việc triệt để). Tuyệt vời. – Pyderman

+0

Nếu cam kết() bằng cách nào đó thất bại, là rollback() cần thiết để từ bỏ các thay đổi từ execute() sao cho commit tiếp theo() (ví dụ của bạn không có) sẽ không nhận được chúng? – Syncopated

+2

thực hành tiêu chuẩn và an toàn cần được tuân theo là: 'try {start transaction; thực hiện các câu lệnh; commit transaction;} catch (Exception e) {thực hiện rollback; } cuối cùng {đóng tài nguyên DB như tuyên bố; } 'Ngoài ra điểm này" _So, logic, rollback là không cần thiết._ "nếu cam kết không xảy ra là không chính xác vì giao dịch sẽ vẫn mở và có thể dẫn đến các vấn đề nghiêm trọng như khởi động lại một giao dịch khác, bạn chưa đóng cửa (cuộn lại). – sactiw

Các vấn đề liên quan