杰瑞科技汇

Python rollback如何实现?

Of course! In Python, rollback() is a crucial method used in database programming to undo a transaction that has not yet been committed.

Python rollback如何实现?-图1
(图片来源网络,侵删)

Let's break it down in detail.

The Core Concept: Transactions and ACID

Before talking about rollback(), you need to understand database transactions.

A transaction is a sequence of one or more operations (like INSERT, UPDATE, DELETE) that are treated as a single, atomic unit. For a transaction to be reliable, it must follow the ACID properties:

  1. Atomicity: The entire transaction must succeed, or the entire transaction must be rolled back. There's no in-between. If one command fails, the whole thing fails.
  2. Consistency: The database must remain in a consistent state before and after the transaction.
  3. Isolation: Concurrent transactions do not interfere with each other.
  4. Durability: Once a transaction is committed, its changes are permanent, even if the system crashes.

rollback() is the mechanism that enforces Atomicity.

Python rollback如何实现?-图2
(图片来源网络,侵删)

How rollback() Works: The Flow

You typically use rollback() in a try...except block. Here's the standard pattern:

  1. Start a Transaction: Most database connectors start a transaction implicitly with the first execute() command after a commit or when a connection is made.
  2. Execute Commands: You run your database operations (e.g., cursor.execute("INSERT INTO ...")).
  3. Commit or Rollback:
    • If all commands succeed, you call connection.commit() to make the changes permanent.
    • If any command raises an exception (an error), you catch it and call connection.rollback() to undo all the changes made in the current transaction.

Concrete Example with sqlite3

Python's built-in sqlite3 module is perfect for a simple, self-contained example.

Let's imagine we have a simple table users:

CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    balance INTEGER NOT NULL
);

Scenario: We want to transfer $100 from "Alice" to "Bob". This requires two UPDATE statements. If the second one fails, we want the first one to be undone as well.

Python rollback如何实现?-图3
(图片来源网络,侵删)
import sqlite3
# --- Setup: Create a database and a table ---
conn = sqlite3.connect(':memory:') # Use an in-memory database for this example
cursor = conn.cursor()
cursor.execute('''
    CREATE TABLE users (
        id INTEGER PRIMARY KEY,
        name TEXT NOT NULL,
        balance INTEGER NOT NULL
    )
''')
# Insert initial data
cursor.execute("INSERT INTO users (name, balance) VALUES (?, ?)", ('Alice', 500))
cursor.execute("INSERT INTO users (name, balance) VALUES (?, ?)", ('Bob', 300))
conn.commit() # Commit the initial setup
print("Initial state: Alice has $500, Bob has $300.")
# --- The Transaction with a potential failure ---
try:
    # 1. Start the transaction (implicit)
    print("\nStarting transaction: Transferring $100 from Alice to Bob...")
    # 2. First operation: Deduct from Alice's account
    cursor.execute("UPDATE users SET balance = balance - 100 WHERE name = 'Alice'")
    print("Step 1: Deducted $100 from Alice's balance.")
    # 3. Simulate an error in the second operation
    # Let's try to update a user that doesn't exist
    cursor.execute("UPDATE users SET balance = balance + 100 WHERE name = 'NonExistentUser'")
    print("Step 2: This line should not be printed if an error occurs.")
    # If we reach here, both commands succeeded. We commit.
    conn.commit()
    print("Transaction committed successfully!")
except sqlite3.Error as e:
    # 4. If any error occurs, we catch it and rollback
    print(f"\nAn error occurred: {e}")
    print("Rolling back the transaction...")
    conn.rollback()
    print("Transaction has been rolled back.")
finally:
    # 5. Always close the connection
    conn.close()
# --- Verification: Let's check the final state ---
# We need a new connection to see the final state of the database
conn_final = sqlite3.connect(':memory:')
cursor_final = conn_final.cursor()
cursor_final.execute("SELECT name, balance FROM users")
results = cursor_final.fetchall()
conn_final.close()
print("\nFinal state of the database:")
for row in results:
    print(f"User: {row[0]}, Balance: ${row[1]}")

Output of the Example:

Initial state: Alice has $500, Bob has $300.
Starting transaction: Transferring $100 from Alice to Bob...
Step 1: Deducted $100 from Alice's balance.
An error occurred: no such column: balance
Rolling back the transaction...
Transaction has been rolled back.
Final state of the database:
User: Alice, Balance: $500
User: Bob, Balance: $300

Explanation of the Output:

  1. The first UPDATE (deducting from Alice) succeeded.
  2. The second UPDATE failed because we tried to update a non-existent table (or in this case, a non-existent column to simulate a real error).
  3. The except block was triggered.
  4. conn.rollback() was called, which undid the first UPDATE. Alice's balance was restored to $500.
  5. The final state shows that no money was transferred, demonstrating the atomicity of the transaction.

Key Takeaways

  1. Purpose: rollback() is used to undo a transaction that has not been commit()ted.
  2. Usage: It's almost always used inside an except block to handle errors.
  3. Connection Object: You call it on the connection object (e.g., conn.rollback()).
  4. Paired with commit(): They are two sides of the same coin.
    • commit(): "Make these changes permanent."
    • rollback(): "Forget these changes ever happened."
  5. Crucial for Data Integrity: It prevents your database from being left in an inconsistent state (e.g., Alice lost $100, but Bob never received it).
  6. Always Close Connections: Use a finally block to ensure your database connection is always closed, regardless of whether the transaction succeeded or was rolled back.
分享:
扫描分享到社交APP
上一篇
下一篇