Python Transaction Management
The `transaction` package provides a generic transaction implementation for Python, offering a two-phase commit protocol. It allows multiple backends (such as ZODB, SQLAlchemy, filesystem, or custom data managers) to participate in a single transaction, ensuring atomicity across diverse storage systems. It also supports savepoints, enabling partial rollbacks. The current version is 5.1, with a release cadence that has seen several major updates over the last few years, maintaining active development.
Warnings
- breaking Recent major versions have dropped support for older Python versions. Specifically, v4.0 dropped Python 2.7, 3.5, 3.6; v5.0 dropped Python 3.7; and v5.1 dropped Python 3.8, 3.9. Always check the release notes for detailed compatibility.
- breaking Version 3.0.0 introduced significant breaking changes by dropping support for legacy transaction APIs, including `Transaction.register()` and older ZODB3-style data managers. The behavior of `TransactionManager.run` also changed, affecting how transactions are committed/aborted after function execution.
- gotcha The default transaction manager (`transaction.manager`) is typically thread-local. In multi-threaded applications or complex asynchronous contexts, improper management can lead to unexpected state or lost changes if transactions are not correctly demarcated for each thread/task.
- gotcha Avoid placing irreversible operations (e.g., external API calls, sending emails, writing to external non-transactional services) or long-running, blocking I/O calls within the scope of a `transaction` block. Transactions hold locks on resources, and such operations can lead to deadlocks, timeouts, or inconsistent states if a rollback becomes necessary.
Install
-
pip install transaction
Imports
- transaction
import transaction
Quickstart
import transaction
# In a real application, 'some_backend_operation()' would interact
# with a data manager (e.g., ZODB, SQLAlchemy session, or a custom one)
# which registers itself with the transaction machinery automatically
# or explicitly.
# For this example, we'll simulate a backend operation.
def some_backend_operation(success=True):
print(f"Performing backend operation (success={success})...")
# In a real scenario, this would be where changes are made
# to a persistent store via a registered data manager.
if not success:
raise ValueError("Simulated backend error!")
print("Backend operation completed.")
try:
# Code block where operations participating in the transaction occur
some_backend_operation(success=True)
# If multiple backends are involved, their operations would be here too
# e.g., db_session.add(some_object), file_manager.write_data()
# Commit the transaction if all operations succeed
print("Attempting to commit transaction...")
transaction.commit()
print("Transaction committed successfully.")
except ValueError as e:
# Rollback the transaction if any operation fails
print(f"Error: {e}. Rolling back transaction...")
transaction.abort()
print("Transaction aborted.")
except Exception as e:
print(f"Unexpected error: {e}. Aborting transaction...")
transaction.abort()