]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
don't encourage "reader/writer" engines in one session
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 14 Aug 2023 14:13:01 +0000 (10:13 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 14 Aug 2023 14:13:01 +0000 (10:13 -0400)
Change-Id: Ia18db210bf22d76147c80e901ac755442faa19be
References: #10233

doc/build/orm/persistence_techniques.rst
doc/build/orm/session_transaction.rst

index dca6cefffd8455ff4a9dd20e61dcf099032d3b77..982f27ebdc676d3465e4cfce52a4c0e045e184de 100644 (file)
@@ -802,6 +802,10 @@ a custom :class:`.Session` which delivers the following rules:
             if mapper and issubclass(mapper.class_, MyOtherClass):
                 return engines["other"]
             elif self._flushing or isinstance(clause, (Update, Delete)):
+                # NOTE: this is for example, however in practice reader/writer
+                # splits are likely more straightforward by using two distinct
+                # Sessions at the top of a "reader" or "writer" operation.
+                # See note below
                 return engines["leader"]
             else:
                 return engines[random.choice(["follower1", "follower2"])]
@@ -815,6 +819,20 @@ This approach can be combined with multiple :class:`_schema.MetaData` objects,
 using an approach such as that of using the declarative ``__abstract__``
 keyword, described at :ref:`declarative_abstract`.
 
+.. note:: While the above example illustrates routing of specific SQL statements
+   to a so-called "leader" or "follower" database based on whether or not the
+   statement expects to write data, this is likely not a practical approach,
+   as it leads to uncoordinated transaction behavior between reading
+   and writing within the same operation.  In practice, it's likely best
+   to construct the :class:`_orm.Session` up front as a "reader" or "writer"
+   session, based on the overall operation / transaction that's proceeding.
+   That way, an operation that will be writing data will also emit its read-queries
+   within the same transaction scope.  See the example at
+   :ref:`session_transaction_isolation_enginewide` for a recipe that sets up
+   one :class:`_orm.sessionmaker` for "read only" operations using autocommit
+   connections, and another for "write" operations which will include DML /
+   COMMIT.
+
 .. seealso::
 
     `Django-style Database Routers in SQLAlchemy <https://techspot.zzzeek.org/2012/01/11/django-style-database-routers-in-sqlalchemy/>`_  - blog post on a more comprehensive example of :meth:`.Session.get_bind`
index 85d1cf50be9c0bbdf5fc8f397a037a4e8fda2131..10da76eda80234cf9822ea8a56f282eee1fbaaf5 100644 (file)
@@ -474,6 +474,8 @@ order to affect transaction isolation level, we need to act upon the
     :ref:`dbapi_autocommit` - be sure to review how isolation levels work at
     the level of the SQLAlchemy :class:`_engine.Connection` object as well.
 
+.. _session_transaction_isolation_enginewide:
+
 Setting Isolation For A Sessionmaker / Engine Wide
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~