.. changelog::
:version: 0.9.9
+ .. change::
+ :tags: enhancement, orm
+ :versions: 1.0.0
+
+ Added new method :meth:`.Session.invalidate`, functions similarly
+ to :meth:`.Session.close`, except also calls
+ :meth:`.Connection.invalidate`
+ on all connections, guaranteeing that they will not be returned to
+ the connection pool. This is useful in situations e.g. dealing
+ with gevent timeouts when it is not safe to use the connection further,
+ even for rollbacks.
+
.. change::
:tags: bug, examples
:versions: 1.0.0
self.session.dispatch.after_rollback(self.session)
- def close(self):
+ def close(self, invalidate=False):
self.session.transaction = self._parent
if self._parent is None:
for connection, transaction, autoclose in \
set(self._connections.values()):
+ if invalidate:
+ connection.invalidate()
if autoclose:
connection.close()
else:
not use any connection resources until they are first needed.
"""
+ self._close_impl(invalidate=False)
+
+ def invalidate(self):
+ """Close this Session, using connection invalidation.
+
+ This is a variant of :meth:`.Session.close` that will additionally
+ ensure that the :meth:`.Connection.invalidate` method will be called
+ on all :class:`.Connection` objects. This can be called when
+ the database is known to be in a state where the connections are
+ no longer safe to be used.
+
+ E.g.::
+
+ try:
+ sess = Session()
+ sess.add(User())
+ sess.commit()
+ except gevent.Timeout:
+ sess.invalidate()
+ raise
+ except:
+ sess.rollback()
+ raise
+
+ This clears all items and ends any transaction in progress.
+
+ If this session were created with ``autocommit=False``, a new
+ transaction is immediately begun. Note that this new transaction does
+ not use any connection resources until they are first needed.
+
+ .. versionadded:: 0.9.9
+
+ """
+ self._close_impl(invalidate=True)
+
+ def _close_impl(self, invalidate):
self.expunge_all()
if self.transaction is not None:
for transaction in self.transaction._iterate_parents():
- transaction.close()
+ transaction.close(invalidate)
def expunge_all(self):
"""Remove all object instances from this ``Session``.
assert users.count().scalar() == 1
assert addresses.count().scalar() == 1
+ @testing.requires.independent_connections
+ def test_invalidate(self):
+ User, users = self.classes.User, self.tables.users
+ mapper(User, users)
+ sess = Session()
+ u = User(name='u1')
+ sess.add(u)
+ sess.flush()
+ c1 = sess.connection(User)
+
+ sess.invalidate()
+ assert c1.invalidated
+
+ eq_(sess.query(User).all(), [])
+ c2 = sess.connection(User)
+ assert not c2.invalidated
+
def test_subtransaction_on_noautocommit(self):
User, users = self.classes.User, self.tables.users