Commits

Mike Bayer committed 06152e5

almost obliterate the concept of "implicit execution" from the docs, move it only
to the "engines and connections" chapter nobody reads, put big green "note:"
boxes with the word "discouraged" in them for "bound metadata", "implicit execution",
"threadlocal strategy"

Comments (0)

Files changed (4)

doc/build/core/connections.rst

   object internally. See :ref:`unitofwork_transaction` for further
   information.
 
-The :class:`~sqlalchemy.engine.Connection` object provides a ``begin()``
-method which returns a :class:`~sqlalchemy.engine.base.Transaction` object.
+The :class:`~sqlalchemy.engine.Connection` object provides a :meth:`~.Connection.begin`
+method which returns a :class:`.Transaction` object.
 This object is usually used within a try/except clause so that it is
-guaranteed to ``rollback()`` or ``commit()``::
+guaranteed to invoke :meth:`.Transaction.rollback` or :meth:`.Transaction.commit`::
 
+    connection = engine.connect()
     trans = connection.begin()
     try:
         r1 = connection.execute(table1.select())
         trans.rollback()
         raise
 
+The above block can be created more succinctly using context
+managers, either given an :class:`.Engine`::
+
+    # runs a transaction
+    with engine.begin() as connection:
+        r1 = connection.execute(table1.select())
+        connection.execute(table1.insert(), col1=7, col2='this is some data')
+
+Or from the :class:`.Connection`, in which case the :class:`.Transaction` object
+is available as well::
+
+    with connection.begin() as trans:
+        r1 = connection.execute(table1.select())
+        connection.execute(table1.insert(), col1=7, col2='this is some data')
+
 .. _connections_nested_transactions:
 
 Nesting of Transaction Blocks
 ------------------------------
 
-The :class:`~sqlalchemy.engine.base.Transaction` object also handles "nested"
+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 Connection, but only the outermost
-Transaction object actually takes effect when it is committed.
+two functions both issue a transaction on a :class:`.Connection`, but only the outermost
+:class:`.Transaction` object actually takes effect when it is committed.
 
 .. sourcecode:: python+sql
 
 usage of :class:`.Connection`. "Connectionless" execution
 refers to the usage of the ``execute()`` method on an object which is not a
 :class:`.Connection`.  This was illustrated using the :meth:`~.Engine.execute` method
-of :class:`.Engine`.
+of :class:`.Engine`::
+
+    result = engine.execute("select username from users")
+    for row in result:
+        print "username:", row['username']
 
 In addition to "connectionless" execution, it is also possible
 to use the :meth:`~.Executable.execute` method of
 
 Given a table as below::
 
+    from sqlalchemy import MetaData, Table, Column, Integer
+
     meta = MetaData()
     users_table = Table('users', meta,
         Column('id', Integer, primary_key=True),
     )
 
 Explicit execution delivers the SQL text or constructed SQL expression to the
-``execute()`` method of :class:`~sqlalchemy.engine.Connection`:
+:meth:`~.Connection.execute` method of :class:`~sqlalchemy.engine.Connection`:
 
 .. sourcecode:: python+sql
 
     connection.close()
 
 Explicit, connectionless execution delivers the expression to the
-``execute()`` method of :class:`~sqlalchemy.engine.Engine`:
+:meth:`~.Engine.execute` method of :class:`~sqlalchemy.engine.Engine`:
 
 .. sourcecode:: python+sql
 
         # ....
     result.close()
 
-Implicit execution is also connectionless, and calls the ``execute()`` method
-on the expression itself, utilizing the fact that either an
+Implicit execution is also connectionless, and makes usage of the :meth:`~.Executable.execute` method
+on the expression itself.   This method is provided as part of the
+:class:`.Executable` class, which refers to a SQL statement that is sufficient
+for being invoked against the database.    The method makes usage of
+the assumption that either an
 :class:`~sqlalchemy.engine.Engine` or
-:class:`~sqlalchemy.engine.Connection` has been *bound* to the expression
-object (binding is discussed further in
-:ref:`metadata_toplevel`):
-
-.. sourcecode:: python+sql
+:class:`~sqlalchemy.engine.Connection` has been **bound** to the expression
+object.   By "bound" we mean that the special attribute :attr:`.MetaData.bind`
+has been used to associate a series of
+:class:`.Table` objects and all SQL constructs derived from them with a specific
+engine::
 
     engine = create_engine('sqlite:///file.db')
     meta.bind = engine
         # ....
     result.close()
 
+Above, we associate an :class:`.Engine` with a :class:`.MetaData` object using
+the special attribute :attr:`.MetaData.bind`.  The :func:`.select` construct produced
+from the :class:`.Table` object has a method :meth:`~.Executable.execute`, which will
+search for an :class:`.Engine` that's "bound" to the :class:`.Table`.
+
+.. note::
+
+    The concepts of "bound metadata" and "implicit execution" are not emphasized in modern SQLAlchemy.
+    In applications
+    where multiple :class:`.Engine` objects are present, each one logically associated
+    with a certain set of tables (i.e. *vertical sharding*), the "bound metadata" technique can be used
+    so that individual :class:`.Table` can refer to the appropriate :class:`.Engine` automatically;
+    in particular this is supported within the ORM via the :class:`.Session` object
+    as a means to associate :class:`.Table` objects with an appropriate :class:`.Engine`,
+    as an alternative to using the bind arguments accepted directly by the :class:`.Session`.
+    However, the "implicit execution" technique is not at all appropriate for use with the
+    ORM, as it bypasses the transactional context maintained by the :class:`.Session`.
+
+    Overall, in the *vast majority* of cases, "bound metadata" and "implicit execution"
+    are **not useful**.   While "bound metadata" has a marginal level of usefulness with regards to
+    ORM configuration, "implicit execution" is a very old usage pattern that in most
+    cases is more confusing than it is helpful, and its usage is discouraged.
+
+    Modern SQLAlchemy usage, especially the ORM, places a heavy stress on working within the context
+    of a transaction at all times; the "implicit execution" concept makes the job of
+    associating statement execution with a particular transaction much more difficult.
+    The :meth:`.Executable.execute` method on a particular SQL statement
+    usually implies that the execution is not part of any particular transaction, which is
+    usually not the desired effect.
+
 In both "connectionless" examples, the
 :class:`~sqlalchemy.engine.Connection` is created behind the scenes; the
 :class:`~sqlalchemy.engine.ResultProxy` returned by the ``execute()``
 with the current thread, such that all parts of the
 application can participate in that transaction implicitly without the need to
 explicitly reference a :class:`.Connection`.
-"threadlocal" is designed for a very specific pattern of use, and is not
-appropriate unless this very specfic pattern, described below, is what's
-desired. It has **no impact** on the "thread safety" of SQLAlchemy components
-or one's application. It also should not be used when using an ORM
-:class:`~sqlalchemy.orm.session.Session` object, as the
-:class:`~sqlalchemy.orm.session.Session` itself represents an ongoing
-transaction and itself handles the job of maintaining connection and
-transactional resources.
+
+.. note::
+
+    The "threadlocal" feature is generally discouraged.   It's
+    designed for a particular pattern of usage which is generally
+    considered as a legacy pattern.  It has **no impact** on the "thread safety"
+    of SQLAlchemy components
+    or one's application. It also should not be used when using an ORM
+    :class:`~sqlalchemy.orm.session.Session` object, as the
+    :class:`~sqlalchemy.orm.session.Session` itself represents an ongoing
+    transaction and itself handles the job of maintaining connection and
+    transactional resources.
 
 Enabling ``threadlocal`` is achieved as follows::
 

doc/build/core/schema.rst

 Binding MetaData to an Engine or Connection
 --------------------------------------------
 
-Notice in the previous section the creator/dropper methods accept an argument
-for the database engine in use. When a schema construct is combined with an
-:class:`~sqlalchemy.engine.Engine` object, or an individual
-:class:`~sqlalchemy.engine.Connection` object, we call this the *bind*.
-In the above examples the bind is associated with the schema construct only
-for the duration of the operation. However, the option exists to persistently
-associate a bind with a set of schema constructs via the
-:class:`~sqlalchemy.schema.MetaData` object's ``bind`` attribute::
-
-    engine = create_engine('sqlite://')
-
-    # create MetaData
-    meta = MetaData()
-
-    # bind to an engine
-    meta.bind = engine
-
-We can now call methods like :func:`~sqlalchemy.schema.MetaData.create_all`
-without needing to pass the :class:`~sqlalchemy.engine.Engine`::
-
-    meta.create_all()
-
-The MetaData's bind is used for anything that requires an active connection,
-such as loading the definition of a table from the database automatically
-(called *reflection*)::
-
-    # describe a table called 'users', query the database for its columns
-    users_table = Table('users', meta, autoload=True)
-
-As well as for executing SQL constructs that are derived from that MetaData's table objects::
-
-    # generate a SELECT statement and execute
-    result = users_table.select().execute()
-
-Binding the MetaData to the Engine is a **completely optional** feature. The
-above operations can be achieved without the persistent bind using
-parameters::
-
-    # describe a table called 'users', query the database for its columns
-    users_table = Table('users', meta, autoload=True, autoload_with=engine)
-
-    # generate a SELECT statement and execute
-    result = engine.execute(users_table.select())
-
-Should you use bind ? It's probably best to start without it, and wait for a
-specific need to arise. Bind is useful if:
-
-* You aren't using the ORM, are usually using "connectionless" execution, and
-  find yourself constantly needing to specify the same
-  :class:`~sqlalchemy.engine.Engine` object throughout the entire
-  application. Bind can be used here to provide "implicit" execution.
-* Your application has multiple schemas that correspond to different engines.
-  Using one :class:`~sqlalchemy.schema.MetaData` for each schema, bound to
-  each engine, provides a decent place to delineate between the schemas. The
-  ORM will also integrate with this approach, where the :class:`.Session` will
-  naturally use the engine that is bound to each table via its metadata
-  (provided the :class:`.Session` itself has no ``bind`` configured.).
-
-Alternatively, the ``bind`` attribute of :class:`~sqlalchemy.schema.MetaData`
-is *confusing* if:
-
-* Your application talks to multiple database engines at different times,
-  which use the *same* set of :class:`.Table` objects. It's usually confusing
-  and unnecessary to begin to create "copies" of :class:`.Table` objects just
-  so that different engines can be used for different operations. An example
-  is an application that writes data to a "master" database while performing
-  read-only operations from a "read slave". A global
-  :class:`~sqlalchemy.schema.MetaData` object is *not* appropriate for
-  per-request switching like this, although a
-  :class:`~sqlalchemy.schema.ThreadLocalMetaData` object is.
-* You are using the ORM :class:`.Session` to handle which class/table is bound
-  to which engine, or you are using the :class:`.Session` to manage switching
-  between engines. Its a good idea to keep the "binding of tables to engines"
-  in one place - either using :class:`~sqlalchemy.schema.MetaData` only (the
-  :class:`.Session` can of course be present, it just has no ``bind``
-  configured), or using :class:`.Session` only (the ``bind`` attribute of
-  :class:`~sqlalchemy.schema.MetaData` is left empty).
+The :class:`.MetaData` object can be associated directly with an :class:`.Engine`
+or :class:`.Connection` so that SQL statement objects gain an :meth:`.Executable.execute`
+method, and also provide an alternate means to the ORM :class:`.Session` object
+in order to locate an :class:`.Engine`, given a particular mapping to execute a
+query against.   However, this pattern is **not recommended for general use**.
+For background, see, :ref:`dbengine_implicit`.
 
 Specifying the Schema Name
 ---------------------------

doc/build/core/tutorial.rst

 assumed that all subsequent argument dictionaries are compatible with that
 statement.
 
-Connectionless / Implicit Execution
-====================================
-
-We're executing our :class:`~sqlalchemy.sql.expression.Insert` using a
-:class:`~sqlalchemy.engine.Connection`. There's two options that allow
-you to not have to deal with the connection part. You can execute in the
-**connectionless** style, using the engine, which checks out from the
-connection pool a connection for you, performs the execute operation with that
-connection, and then checks the connection back into the pool upon completion
-of the operation:
-
-.. sourcecode:: pycon+sql
-
-    {sql}>>> result = engine.execute(users.insert(), name='fred', fullname="Fred Flintstone")
-    INSERT INTO users (name, fullname) VALUES (?, ?)
-    ('fred', 'Fred Flintstone')
-    COMMIT
-
-and you can save even more steps than that, if you connect the
-:class:`~sqlalchemy.engine.Engine` to the
-:class:`~sqlalchemy.schema.MetaData` object we created earlier. When this is
-done, all SQL expressions which involve tables within the
-:class:`~sqlalchemy.schema.MetaData` object will be automatically **bound** to
-the :class:`~sqlalchemy.engine.Engine`. In this case, we call it
-**implicit execution**:
-
-.. sourcecode:: pycon+sql
-
-    >>> metadata.bind = engine
-    {sql}>>> result = users.insert().execute(name="mary", fullname="Mary Contrary")
-    INSERT INTO users (name, fullname) VALUES (?, ?)
-    ('mary', 'Mary Contrary')
-    COMMIT
-
-When the :class:`~sqlalchemy.schema.MetaData` is bound, statements will also
-compile against the engine's dialect. Since a lot of the examples here assume
-the default dialect, we'll detach the engine from the metadata which we just
-attached:
-
-.. sourcecode:: pycon+sql
-
-    >>> metadata.bind = None
-
-Detailed examples of connectionless and implicit execution are available in
-the "Engines" chapter: :ref:`dbengine_implicit`.
-
 .. _coretutorial_selecting:
 
 Selecting

lib/sqlalchemy/schema.py

         return self._bind is not None
 
     def bind(self):
-        """An Engine or Connection to which this MetaData is bound.
-
-        This property may be assigned an ``Engine`` or ``Connection``, or
-        assigned a string or URL to automatically create a basic ``Engine``
-        for this bind with ``create_engine()``.
+        """An :class:`.Engine` or :class:`.Connection` to which this
+        :class:`.MetaData` is bound.
+
+        Typically, a :class:`.Engine` is assigned to this attribute
+        so that "implicit execution" may be used, or alternatively
+        as a means of providing engine binding information to an
+        ORM :class:`.Session` object::
+
+            engine = create_engine("someurl://")
+            metadata.bind = engine
+
+        .. seealso::
+
+           :ref:`dbengine_implicit` - background on "bound metadata"
 
         """
         return self._bind