summaryrefslogtreecommitdiff
path: root/doc/build
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-05-14 12:50:11 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2020-05-17 16:32:22 -0400
commit0e53221eef50b3274841fbd1eb41e32f5dfc4e69 (patch)
treee1c13d067b0db5e0aeee8b934dc0f934154ef9f3 /doc/build
parent79de84b25e87bbb7fa94f0dd513b4abc76e05a7e (diff)
downloadsqlalchemy-0e53221eef50b3274841fbd1eb41e32f5dfc4e69.tar.gz
Update transaction / connection handling
step one, do away with __connection attribute and using awkward AttributeError logic step two, move all management of "connection._transaction" into the transaction objects themselves where it's easier to follow. build MarkerTransaction that takes the role of "do-nothing block" new connection datamodel is: connection._transaction, always a root, connection._nested_transaction, always a nested. nested transactions still chain to each other as this is still sort of necessary but they consider the root transaction separately, and the marker transactions not at all. introduce new InvalidRequestError subclass PendingRollbackError. Apply to connection and session for all cases where a transaction needs to be rolled back before continuing. Within Connection, both PendingRollbackError as well as ResourceClosedError are now raised directly without being handled by handle_dbapi_error(); this removes these two exception cases from the handle_error event handler as well as from StatementError wrapping, as these two exceptions are not statement oriented and are instead programmatic issues, that the application is failing to handle database errors properly. Revise savepoints so that when a release fails, they set themselves as inactive so that their rollback() method does not throw another exception. Give savepoints another go on MySQL, can't get release working however get support for basic round trip going Fixes: #5327 Change-Id: Ia3cbbf56d4882fcc7980f90519412f1711fae74d
Diffstat (limited to 'doc/build')
-rw-r--r--doc/build/errors.rst62
1 files changed, 42 insertions, 20 deletions
diff --git a/doc/build/errors.rst b/doc/build/errors.rst
index 599b91e26..9af96f9b9 100644
--- a/doc/build/errors.rst
+++ b/doc/build/errors.rst
@@ -225,47 +225,69 @@ sooner.
:ref:`connections_toplevel`
+.. _error_8s2b:
+
+Can't reconnect until invalid transaction is rolled back
+----------------------------------------------------------
+
+This error condition refers to the case where a :class:`_engine.Connection` was
+invalidated, either due to a database disconnect detection or due to an
+explicit call to :meth:`_engine.Connection.invalidate`, but there is still a
+transaction present that was initiated by the :meth:`_engine.Connection.begin`
+method. When a connection is invalidated, any :class:`_engine.Transaction`
+that was in progress is now in an invalid state, and must be explicitly rolled
+back in order to remove it from the :class:`_engine.Connection`.
+
.. _error_8s2a:
This connection is on an inactive transaction. Please rollback() fully before proceeding
------------------------------------------------------------------------------------------
This error condition was added to SQLAlchemy as of version 1.4. The error
-refers to the state where a :class:`_engine.Connection` is placed into a transaction
-using a method like :meth:`_engine.Connection.begin`, and then a further "sub" transaction
-is created within that scope; the "sub" transaction is then rolled back using
-:meth:`.Transaction.rollback`, however the outer transaction is not rolled back.
+refers to the state where a :class:`_engine.Connection` is placed into a
+transaction using a method like :meth:`_engine.Connection.begin`, and then a
+further "marker" transaction is created within that scope; the "marker"
+transaction is then rolled back using :meth:`.Transaction.rollback` or closed
+using :meth:`.Transaction.close`, however the outer transaction is still
+present in an "inactive" state and must be rolled back.
The pattern looks like::
engine = create_engine(...)
connection = engine.connect()
- transaction = connection.begin()
+ transaction1 = connection.begin()
+ # this is a "sub" or "marker" transaction, a logical nesting
+ # structure based on "real" transaction transaction1
transaction2 = connection.begin()
transaction2.rollback()
- connection.execute(text("select 1")) # we are rolled back; will now raise
+ # transaction1 is still present and needs explicit rollback,
+ # so this will raise
+ connection.execute(text("select 1"))
- transaction.rollback()
+Above, ``transaction2`` is a "marker" transaction, which indicates a logical
+nesting of transactions within an outer one; while the inner transaction
+can roll back the whole transaction via its rollback() method, its commit()
+method has no effect except to close the scope of the "marker" transaction
+itself. The call to ``transaction2.rollback()`` has the effect of
+**deactivating** transaction1 which means it is essentially rolled back
+at the database level, however is still present in order to accommodate
+a consistent nesting pattern of transactions.
+The correct resolution is to ensure the outer transaction is also
+rolled back::
-Above, ``transaction2`` is a "sub" transaction, which indicates a logical
-nesting of transactions within an outer one. SQLAlchemy makes great use of
-this pattern more commonly in the ORM :class:`.Session`, where the FAQ entry
-:ref:`faq_session_rollback` describes the rationale within the ORM.
+ transaction1.rollback()
-The "subtransaction" pattern in Core comes into play often when using the ORM
-pattern described at :ref:`session_external_transaction`. As this pattern
-involves a behavior called "connection branching", where a :class:`_engine.Connection`
-serves a "branched" :class:`_engine.Connection` object to the :class:`.Session` via
-its :meth:`_engine.Connection.connect` method, the same transaction behavior comes
-into play; if the :class:`.Session` rolls back the transaction, and savepoints
-have not been used to prevent a rollback of the entire transaction, the
-outermost transaction started on the :class:`_engine.Connection` is now in an inactive
-state.
+This pattern is not commonly used in Core. Within the ORM, a similar issue can
+occur which is the product of the ORM's "logical" transaction structure; this
+is described in the FAQ entry at :ref:`faq_session_rollback`.
+The "subtransaction" pattern is to be removed in SQLAlchemy 2.0 so that this
+particular programming pattern will no longer be available and this
+error message will no longer occur in Core.
.. _error_dbapi: