summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2021-11-07 21:19:45 +0000
committerGerrit Code Review <gerrit@ci3.zzzcomputing.com>2021-11-07 21:19:45 +0000
commit201c00bc0837af831f115e8313ad3ccb0be97e7a (patch)
treebeb7558e95d073b63fa4bb76d830ccaa2de9711a /doc
parent5b1c9053b0903b2d5a06f82b47fe16a870696ddc (diff)
parentd050193daaa8d91371c759296f3304b8641c1976 (diff)
downloadsqlalchemy-201c00bc0837af831f115e8313ad3ccb0be97e7a.tar.gz
Merge "fully implement future engine and remove legacy" into main
Diffstat (limited to 'doc')
-rw-r--r--doc/build/core/connections.rst205
-rw-r--r--doc/build/core/future.rst39
-rw-r--r--doc/build/core/pooling.rst5
-rw-r--r--doc/build/errors.rst60
-rw-r--r--doc/build/glossary.rst20
-rw-r--r--doc/build/orm/session_api.rst9
6 files changed, 42 insertions, 296 deletions
diff --git a/doc/build/core/connections.rst b/doc/build/core/connections.rst
index 1139e9224..787500c32 100644
--- a/doc/build/core/connections.rst
+++ b/doc/build/core/connections.rst
@@ -126,189 +126,6 @@ The underlying object used to represent the transaction is the
manager calling form, which invokes these methods automatically, is recommended
as a best practice.
-.. _connections_nested_transactions:
-
-Nesting of Transaction Blocks
------------------------------
-
-.. deprecated:: 1.4 The "transaction nesting" feature of SQLAlchemy is a legacy feature
- that is deprecated in the 1.4 release and will be removed in SQLAlchemy 2.0.
- The pattern has proven to be a little too awkward and complicated, unless an
- application makes more of a first-class framework around the behavior. See
- the following subsection :ref:`connections_avoid_nesting`.
-
-The :class:`.Transaction` object also handles "nested" behavior by keeping
-track of the outermost begin/commit pair. In this example, two functions both
-issue a transaction on a :class:`_engine.Connection`, but only the outermost
-:class:`.Transaction` object actually takes effect when it is committed.
-
-.. sourcecode:: python+sql
-
- # method_a starts a transaction and calls method_b
- def method_a(connection):
- with connection.begin(): # open a transaction
- method_b(connection)
-
- # method_b also starts a transaction
- def method_b(connection):
- with connection.begin(): # open a transaction - this runs in the
- # context of method_a's transaction
- connection.execute(text("insert into mytable values ('bat', 'lala')"))
- connection.execute(mytable.insert(), {"col1": "bat", "col2": "lala"})
-
- # open a Connection and call method_a
- with engine.connect() as conn:
- method_a(conn)
-
-Above, ``method_a`` is called first, which calls ``connection.begin()``. Then
-it calls ``method_b``. When ``method_b`` calls ``connection.begin()``, it just
-increments a counter that is decremented when it calls ``commit()``. If either
-``method_a`` or ``method_b`` calls ``rollback()``, the whole transaction is
-rolled back. The transaction is not committed until ``method_a`` calls the
-``commit()`` method. This "nesting" behavior allows the creation of functions
-which "guarantee" that a transaction will be used if one was not already
-available, but will automatically participate in an enclosing transaction if
-one exists.
-
-.. _connections_avoid_nesting:
-
-Arbitrary Transaction Nesting as an Antipattern
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-With many years of experience, the above "nesting" pattern has not proven to
-be very popular, and where it has been observed in large projects such
-as Openstack, it tends to be complicated.
-
-The most ideal way to organize an application would have a single, or at
-least very few, points at which the "beginning" and "commit" of all
-database transactions is demarcated. This is also the general
-idea discussed in terms of the ORM at :ref:`session_faq_whentocreate`. To
-adapt the example from the previous section to this practice looks like::
-
-
- # method_a calls method_b
- def method_a(connection):
- method_b(connection)
-
- # method_b uses the connection and assumes the transaction
- # is external
- def method_b(connection):
- connection.execute(text("insert into mytable values ('bat', 'lala')"))
- connection.execute(mytable.insert(), {"col1": "bat", "col2": "lala"})
-
- # open a Connection inside of a transaction and call method_a
- with engine.begin() as conn:
- method_a(conn)
-
-That is, ``method_a()`` and ``method_b()`` do not deal with the details
-of the transaction at all; the transactional scope of the connection is
-defined **externally** to the functions that have a SQL dialogue with the
-connection.
-
-It may be observed that the above code has fewer lines, and less indentation
-which tends to correlate with lower :term:`cyclomatic complexity`. The
-above code is organized such that ``method_a()`` and ``method_b()`` are always
-invoked from a point at which a transaction is begun. The previous
-version of the example features a ``method_a()`` and a ``method_b()`` that are
-trying to be agnostic of this fact, which suggests they are prepared for
-at least twice as many potential codepaths through them.
-
-.. _connections_subtransactions:
-
-Migrating from the "nesting" pattern
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-As SQLAlchemy's intrinsic-nested pattern is considered legacy, an application
-that for either legacy or novel reasons still seeks to have a context that
-automatically frames transactions should seek to maintain this functionality
-through the use of a custom Python context manager. A similar example is also
-provided in terms of the ORM in the "seealso" section below.
-
-To provide backwards compatibility for applications that make use of this
-pattern, the following context manager or a similar implementation based on
-a decorator may be used::
-
- import contextlib
-
- @contextlib.contextmanager
- def transaction(connection):
- if not connection.in_transaction():
- with connection.begin():
- yield connection
- else:
- yield connection
-
-The above contextmanager would be used as::
-
- # method_a starts a transaction and calls method_b
- def method_a(connection):
- with transaction(connection): # open a transaction
- method_b(connection)
-
- # method_b either starts a transaction, or uses the one already
- # present
- def method_b(connection):
- with transaction(connection): # open a transaction
- connection.execute(text("insert into mytable values ('bat', 'lala')"))
- connection.execute(mytable.insert(), {"col1": "bat", "col2": "lala"})
-
- # open a Connection and call method_a
- with engine.connect() as conn:
- method_a(conn)
-
-A similar approach may be taken such that connectivity is established
-on demand as well; the below approach features a single-use context manager
-that accesses an enclosing state in order to test if connectivity is already
-present::
-
- import contextlib
-
- def connectivity(engine):
- connection = None
-
- @contextlib.contextmanager
- def connect():
- nonlocal connection
-
- if connection is None:
- connection = engine.connect()
- with connection:
- with connection.begin():
- yield connection
- else:
- yield connection
-
- return connect
-
-Using the above would look like::
-
- # method_a passes along connectivity context, at the same time
- # it chooses to establish a connection by calling "with"
- def method_a(connectivity):
- with connectivity():
- method_b(connectivity)
-
- # method_b also wants to use a connection from the context, so it
- # also calls "with:", but also it actually uses the connection.
- def method_b(connectivity):
- with connectivity() as connection:
- connection.execute(text("insert into mytable values ('bat', 'lala')"))
- connection.execute(mytable.insert(), {"col1": "bat", "col2": "lala"})
-
- # create a new connection/transaction context object and call
- # method_a
- method_a(connectivity(engine))
-
-The above context manager acts not only as a "transaction" context but also
-as a context that manages having an open connection against a particular
-:class:`_engine.Engine`. When using the ORM :class:`_orm.Session`, this
-connectivty management is provided by the :class:`_orm.Session` itself.
-An overview of ORM connectivity patterns is at :ref:`unitofwork_transaction`.
-
-.. seealso::
-
- :ref:`session_subtransactions` - ORM version
-
.. _autocommit:
Library Level (e.g. emulated) Autocommit
@@ -418,18 +235,16 @@ begin a transaction::
with connection.begin():
connection.execute(<statement>)
-.. note:: The return value of
- the :meth:`_engine.Connection.execution_options` method is a so-called
- "branched" connection under the SQLAlchemy 1.x series when not using
- :paramref:`_sa.create_engine.future` mode, which is a shallow
- copy of the original :class:`_engine.Connection` object. Despite this,
- the ``isolation_level`` execution option applies to the
- original :class:`_engine.Connection` object and all "branches" overall.
-
- When using :paramref:`_sa.create_engine.future` mode (i.e. :term:`2.0 style`
- usage), the concept of these so-called "branched" connections is removed,
- and :meth:`_engine.Connection.execution_options` returns the **same**
- :class:`_engine.Connection` object without creating any copies.
+.. tip:: The return value of
+ the :meth:`_engine.Connection.execution_options` method is the same
+ :class:`_engine.Connection` object upon which the method was called,
+ meaning, it modifies the state of the :class:`_engine.Connection`
+ object in place. This is a new behavior as of SQLAlchemy 2.0.
+ This behavior does not apply to the :meth:`_engine.Engine.execution_options`
+ method; that method still returns a copy of the :class:`.Engine` and
+ as described below may be used to construct multiple :class:`.Engine`
+ objects with different execution options, which nonetheless share the same
+ dialect and connection pool.
The :paramref:`_engine.Connection.execution_options.isolation_level` option may
also be set engine wide, as is often preferable. This is achieved by
diff --git a/doc/build/core/future.rst b/doc/build/core/future.rst
index 204e40135..1174f7d0a 100644
--- a/doc/build/core/future.rst
+++ b/doc/build/core/future.rst
@@ -4,42 +4,19 @@ SQLAlchemy 2.0 Future (Core)
============================
This package includes a relatively small number of transitional elements
-to allow "2.0 mode" to take place within SQLAlchemy 1.4. The primary
-objects provided here are :class:`_future.Engine` and :class:`_future.Connection`,
-which are both subclasses of the existing :class:`_engine.Engine` and
-:class:`_engine.Connection` objects with essentially a smaller set of
-methods and the removal of "autocommit".
+to allow "2.0 mode" to take place within SQLAlchemy 1.4.
-Within the 1.4 series, the "2.0" style of engines and connections is enabled
-by passing the :paramref:`_sa.create_engine.future` flag to
-:func:`_sa.create_engine`::
+In the 2.0 release of SQLAlchemy, the objects published here are the same
+:class:`_engine.Engine`, :class:`_engine.Connection` and
+:func:`_sa.create_engine` classes and functions that are
+used by default. The package is here for backwards compatibility with
+SQLAlchemy 1.4.
- from sqlalchemy import create_engine
- engine = create_engine("postgresql://user:pass@host/dbname", future=True)
-
-Similarly, with the ORM, to enable "future" behavior in the ORM :class:`.Session`,
-pass the :paramref:`_orm.Session.future` parameter either to the
-:class:`.Session` constructor directly, or via the :class:`_orm.sessionmaker`
-class::
-
- from sqlalchemy.orm import sessionmaker
-
- Session = sessionmaker(engine, future=True)
+The ``sqlalchemy.future`` package will be deprecated in a subsequent
+2.x release and eventually removed.
.. seealso::
:ref:`migration_20_toplevel` - Introduction to the 2.0 series of SQLAlchemy
-.. module:: sqlalchemy.future
-
-.. autoclass:: sqlalchemy.future.Connection
- :members:
-
-.. autofunction:: sqlalchemy.future.create_engine
-
-.. autoclass:: sqlalchemy.future.Engine
- :members:
-
-.. autofunction:: sqlalchemy.future.select
-
diff --git a/doc/build/core/pooling.rst b/doc/build/core/pooling.rst
index 858f8b0f5..d0629a4a1 100644
--- a/doc/build/core/pooling.rst
+++ b/doc/build/core/pooling.rst
@@ -266,8 +266,9 @@ behaviors are needed::
@event.listens_for(some_engine, "engine_connect")
def ping_connection(connection, branch):
if branch:
- # "branch" refers to a sub-connection of a connection,
- # we don't want to bother pinging on these.
+ # this parameter is always False as of SQLAlchemy 2.0,
+ # but is still accepted by the event hook. In 1.x versions
+ # of SQLAlchemy, "branched" connections should be skipped.
return
try:
diff --git a/doc/build/errors.rst b/doc/build/errors.rst
index 2b163ec26..2318d39b0 100644
--- a/doc/build/errors.rst
+++ b/doc/build/errors.rst
@@ -536,68 +536,18 @@ sooner.
.. _error_8s2b:
-Can't reconnect until invalid transaction is rolled back
-----------------------------------------------------------
+Can't reconnect until invalid transaction is rolled back. Please rollback() fully before proceeding
+-----------------------------------------------------------------------------------------------------
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`
+transaction present that was initiated either explicitly by the :meth:`_engine.Connection.begin`
+method, or due to the connection automatically beginning a transaction as occurs
+in the 2.x series of SQLAlchemy when any SQL statements are emitted. 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 "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()
- transaction1 = connection.begin()
-
- # this is a "sub" or "marker" transaction, a logical nesting
- # structure based on "real" transaction transaction1
- transaction2 = connection.begin()
- transaction2.rollback()
-
- # transaction1 is still present and needs explicit rollback,
- # so this will raise
- connection.execute(text("select 1"))
-
-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::
-
- transaction1.rollback()
-
-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:
DBAPI Errors
diff --git a/doc/build/glossary.rst b/doc/build/glossary.rst
index f979df147..88980195b 100644
--- a/doc/build/glossary.rst
+++ b/doc/build/glossary.rst
@@ -522,16 +522,14 @@ Glossary
of classes; "joined", "single", and "concrete". The section
:ref:`inheritance_toplevel` describes inheritance mapping fully.
- generative
- A term that SQLAlchemy uses to refer what's normally known
- as :term:`method chaining`; see that term for details.
-
method chaining
- An object-oriented technique whereby the state of an object
- is constructed by calling methods on the object. The
- object features any number of methods, each of which return
- a new object (or in some cases the same object) with
- additional state added to the object.
+ generative
+ "Method chaining", referred to within SQLAlchemy documentation as
+ "generative", is an object-oriented technique whereby the state of an
+ object is constructed by calling methods on the object. The object
+ features any number of methods, each of which return a new object (or
+ in some cases the same object) with additional state added to the
+ object.
The two SQLAlchemy objects that make the most use of
method chaining are the :class:`_expression.Select`
@@ -550,10 +548,6 @@ Glossary
:class:`_expression.Select` object with additional qualifiers
added.
- .. seealso::
-
- :term:`generative`
-
release
releases
released
diff --git a/doc/build/orm/session_api.rst b/doc/build/orm/session_api.rst
index ada035e95..93f9541f7 100644
--- a/doc/build/orm/session_api.rst
+++ b/doc/build/orm/session_api.rst
@@ -46,11 +46,20 @@ Session and sessionmaker()
:attr:`_orm.ORMExecuteState.execution_options`
.. attribute:: execution_options
+
The complete dictionary of current execution options.
This is a merge of the statement level options with the
locally passed execution options.
+ .. seealso::
+
+ :attr:`_orm.ORMExecuteState.local_execution_options`
+
+ :meth:`_sql.Executable.execution_options`
+
+ :ref:`orm_queryguide_execution_options`
+
.. autoclass:: Session
:members:
:inherited-members: