/lib/sqlalchemy/orm/session.py

https://github.com/biznixcn/sqlalchemy · Python · 2445 lines · 1997 code · 174 blank · 274 comment · 145 complexity · 13693bd16d5c462672f2bc6d693fae84 MD5 · raw file

Large files are truncated click here to view the full file

  1. # orm/session.py
  2. # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors <see AUTHORS file>
  3. #
  4. # This module is part of SQLAlchemy and is released under
  5. # the MIT License: http://www.opensource.org/licenses/mit-license.php
  6. """Provides the Session class and related utilities."""
  7. import weakref
  8. from .. import util, sql, engine, exc as sa_exc
  9. from ..sql import util as sql_util, expression
  10. from . import (
  11. SessionExtension, attributes, exc, query,
  12. loading, identity
  13. )
  14. from ..inspection import inspect
  15. from .base import (
  16. object_mapper, class_mapper,
  17. _class_to_mapper, _state_mapper, object_state,
  18. _none_set, state_str, instance_str
  19. )
  20. from .unitofwork import UOWTransaction
  21. from . import state as statelib
  22. import sys
  23. __all__ = ['Session', 'SessionTransaction', 'SessionExtension', 'sessionmaker']
  24. _sessions = weakref.WeakValueDictionary()
  25. """Weak-referencing dictionary of :class:`.Session` objects.
  26. """
  27. def _state_session(state):
  28. """Given an :class:`.InstanceState`, return the :class:`.Session`
  29. associated, if any.
  30. """
  31. if state.session_id:
  32. try:
  33. return _sessions[state.session_id]
  34. except KeyError:
  35. pass
  36. return None
  37. class _SessionClassMethods(object):
  38. """Class-level methods for :class:`.Session`, :class:`.sessionmaker`."""
  39. @classmethod
  40. def close_all(cls):
  41. """Close *all* sessions in memory."""
  42. for sess in _sessions.values():
  43. sess.close()
  44. @classmethod
  45. @util.dependencies("sqlalchemy.orm.util")
  46. def identity_key(cls, orm_util, *args, **kwargs):
  47. """Return an identity key.
  48. This is an alias of :func:`.util.identity_key`.
  49. """
  50. return orm_util.identity_key(*args, **kwargs)
  51. @classmethod
  52. def object_session(cls, instance):
  53. """Return the :class:`.Session` to which an object belongs.
  54. This is an alias of :func:`.object_session`.
  55. """
  56. return object_session(instance)
  57. ACTIVE = util.symbol('ACTIVE')
  58. PREPARED = util.symbol('PREPARED')
  59. COMMITTED = util.symbol('COMMITTED')
  60. DEACTIVE = util.symbol('DEACTIVE')
  61. CLOSED = util.symbol('CLOSED')
  62. class SessionTransaction(object):
  63. """A :class:`.Session`-level transaction.
  64. :class:`.SessionTransaction` is a mostly behind-the-scenes object
  65. not normally referenced directly by application code. It coordinates
  66. among multiple :class:`.Connection` objects, maintaining a database
  67. transaction for each one individually, committing or rolling them
  68. back all at once. It also provides optional two-phase commit behavior
  69. which can augment this coordination operation.
  70. The :attr:`.Session.transaction` attribute of :class:`.Session`
  71. refers to the current :class:`.SessionTransaction` object in use, if any.
  72. A :class:`.SessionTransaction` is associated with a :class:`.Session`
  73. in its default mode of ``autocommit=False`` immediately, associated
  74. with no database connections. As the :class:`.Session` is called upon
  75. to emit SQL on behalf of various :class:`.Engine` or :class:`.Connection`
  76. objects, a corresponding :class:`.Connection` and associated
  77. :class:`.Transaction` is added to a collection within the
  78. :class:`.SessionTransaction` object, becoming one of the
  79. connection/transaction pairs maintained by the
  80. :class:`.SessionTransaction`.
  81. The lifespan of the :class:`.SessionTransaction` ends when the
  82. :meth:`.Session.commit`, :meth:`.Session.rollback` or
  83. :meth:`.Session.close` methods are called. At this point, the
  84. :class:`.SessionTransaction` removes its association with its parent
  85. :class:`.Session`. A :class:`.Session` that is in ``autocommit=False``
  86. mode will create a new :class:`.SessionTransaction` to replace it
  87. immediately, whereas a :class:`.Session` that's in ``autocommit=True``
  88. mode will remain without a :class:`.SessionTransaction` until the
  89. :meth:`.Session.begin` method is called.
  90. Another detail of :class:`.SessionTransaction` behavior is that it is
  91. capable of "nesting". This means that the :meth:`.Session.begin` method
  92. can be called while an existing :class:`.SessionTransaction` is already
  93. present, producing a new :class:`.SessionTransaction` that temporarily
  94. replaces the parent :class:`.SessionTransaction`. When a
  95. :class:`.SessionTransaction` is produced as nested, it assigns itself to
  96. the :attr:`.Session.transaction` attribute. When it is ended via
  97. :meth:`.Session.commit` or :meth:`.Session.rollback`, it restores its
  98. parent :class:`.SessionTransaction` back onto the
  99. :attr:`.Session.transaction` attribute. The behavior is effectively a
  100. stack, where :attr:`.Session.transaction` refers to the current head of
  101. the stack.
  102. The purpose of this stack is to allow nesting of
  103. :meth:`.Session.rollback` or :meth:`.Session.commit` calls in context
  104. with various flavors of :meth:`.Session.begin`. This nesting behavior
  105. applies to when :meth:`.Session.begin_nested` is used to emit a
  106. SAVEPOINT transaction, and is also used to produce a so-called
  107. "subtransaction" which allows a block of code to use a
  108. begin/rollback/commit sequence regardless of whether or not its enclosing
  109. code block has begun a transaction. The :meth:`.flush` method, whether
  110. called explicitly or via autoflush, is the primary consumer of the
  111. "subtransaction" feature, in that it wishes to guarantee that it works
  112. within in a transaction block regardless of whether or not the
  113. :class:`.Session` is in transactional mode when the method is called.
  114. See also:
  115. :meth:`.Session.rollback`
  116. :meth:`.Session.commit`
  117. :meth:`.Session.begin`
  118. :meth:`.Session.begin_nested`
  119. :attr:`.Session.is_active`
  120. :meth:`.SessionEvents.after_commit`
  121. :meth:`.SessionEvents.after_rollback`
  122. :meth:`.SessionEvents.after_soft_rollback`
  123. """
  124. _rollback_exception = None
  125. def __init__(self, session, parent=None, nested=False):
  126. self.session = session
  127. self._connections = {}
  128. self._parent = parent
  129. self.nested = nested
  130. self._state = ACTIVE
  131. if not parent and nested:
  132. raise sa_exc.InvalidRequestError(
  133. "Can't start a SAVEPOINT transaction when no existing "
  134. "transaction is in progress")
  135. if self.session._enable_transaction_accounting:
  136. self._take_snapshot()
  137. if self.session.dispatch.after_transaction_create:
  138. self.session.dispatch.after_transaction_create(self.session, self)
  139. @property
  140. def is_active(self):
  141. return self.session is not None and self._state is ACTIVE
  142. def _assert_active(self, prepared_ok=False,
  143. rollback_ok=False,
  144. deactive_ok=False,
  145. closed_msg="This transaction is closed"):
  146. if self._state is COMMITTED:
  147. raise sa_exc.InvalidRequestError(
  148. "This session is in 'committed' state; no further "
  149. "SQL can be emitted within this transaction."
  150. )
  151. elif self._state is PREPARED:
  152. if not prepared_ok:
  153. raise sa_exc.InvalidRequestError(
  154. "This session is in 'prepared' state; no further "
  155. "SQL can be emitted within this transaction."
  156. )
  157. elif self._state is DEACTIVE:
  158. if not deactive_ok and not rollback_ok:
  159. if self._rollback_exception:
  160. raise sa_exc.InvalidRequestError(
  161. "This Session's transaction has been rolled back "
  162. "due to a previous exception during flush."
  163. " To begin a new transaction with this Session, "
  164. "first issue Session.rollback()."
  165. " Original exception was: %s"
  166. % self._rollback_exception
  167. )
  168. elif not deactive_ok:
  169. raise sa_exc.InvalidRequestError(
  170. "This Session's transaction has been rolled back "
  171. "by a nested rollback() call. To begin a new "
  172. "transaction, issue Session.rollback() first."
  173. )
  174. elif self._state is CLOSED:
  175. raise sa_exc.ResourceClosedError(closed_msg)
  176. @property
  177. def _is_transaction_boundary(self):
  178. return self.nested or not self._parent
  179. def connection(self, bindkey, **kwargs):
  180. self._assert_active()
  181. bind = self.session.get_bind(bindkey, **kwargs)
  182. return self._connection_for_bind(bind)
  183. def _begin(self, nested=False):
  184. self._assert_active()
  185. return SessionTransaction(
  186. self.session, self, nested=nested)
  187. def _iterate_parents(self, upto=None):
  188. if self._parent is upto:
  189. return (self,)
  190. else:
  191. if self._parent is None:
  192. raise sa_exc.InvalidRequestError(
  193. "Transaction %s is not on the active transaction list" % (
  194. upto))
  195. return (self,) + self._parent._iterate_parents(upto)
  196. def _take_snapshot(self):
  197. if not self._is_transaction_boundary:
  198. self._new = self._parent._new
  199. self._deleted = self._parent._deleted
  200. self._dirty = self._parent._dirty
  201. self._key_switches = self._parent._key_switches
  202. return
  203. if not self.session._flushing:
  204. self.session.flush()
  205. self._new = weakref.WeakKeyDictionary()
  206. self._deleted = weakref.WeakKeyDictionary()
  207. self._dirty = weakref.WeakKeyDictionary()
  208. self._key_switches = weakref.WeakKeyDictionary()
  209. def _restore_snapshot(self, dirty_only=False):
  210. assert self._is_transaction_boundary
  211. for s in set(self._new).union(self.session._new):
  212. self.session._expunge_state(s)
  213. if s.key:
  214. del s.key
  215. for s, (oldkey, newkey) in self._key_switches.items():
  216. self.session.identity_map.discard(s)
  217. s.key = oldkey
  218. self.session.identity_map.replace(s)
  219. for s in set(self._deleted).union(self.session._deleted):
  220. if s.deleted:
  221. #assert s in self._deleted
  222. del s.deleted
  223. self.session._update_impl(s, discard_existing=True)
  224. assert not self.session._deleted
  225. for s in self.session.identity_map.all_states():
  226. if not dirty_only or s.modified or s in self._dirty:
  227. s._expire(s.dict, self.session.identity_map._modified)
  228. def _remove_snapshot(self):
  229. assert self._is_transaction_boundary
  230. if not self.nested and self.session.expire_on_commit:
  231. for s in self.session.identity_map.all_states():
  232. s._expire(s.dict, self.session.identity_map._modified)
  233. for s in self._deleted:
  234. s.session_id = None
  235. self._deleted.clear()
  236. def _connection_for_bind(self, bind):
  237. self._assert_active()
  238. if bind in self._connections:
  239. return self._connections[bind][0]
  240. if self._parent:
  241. conn = self._parent._connection_for_bind(bind)
  242. if not self.nested:
  243. return conn
  244. else:
  245. if isinstance(bind, engine.Connection):
  246. conn = bind
  247. if conn.engine in self._connections:
  248. raise sa_exc.InvalidRequestError(
  249. "Session already has a Connection associated for the "
  250. "given Connection's Engine")
  251. else:
  252. conn = bind.contextual_connect()
  253. if self.session.twophase and self._parent is None:
  254. transaction = conn.begin_twophase()
  255. elif self.nested:
  256. transaction = conn.begin_nested()
  257. else:
  258. transaction = conn.begin()
  259. self._connections[conn] = self._connections[conn.engine] = \
  260. (conn, transaction, conn is not bind)
  261. self.session.dispatch.after_begin(self.session, self, conn)
  262. return conn
  263. def prepare(self):
  264. if self._parent is not None or not self.session.twophase:
  265. raise sa_exc.InvalidRequestError(
  266. "'twophase' mode not enabled, or not root transaction; "
  267. "can't prepare.")
  268. self._prepare_impl()
  269. def _prepare_impl(self):
  270. self._assert_active()
  271. if self._parent is None or self.nested:
  272. self.session.dispatch.before_commit(self.session)
  273. stx = self.session.transaction
  274. if stx is not self:
  275. for subtransaction in stx._iterate_parents(upto=self):
  276. subtransaction.commit()
  277. if not self.session._flushing:
  278. for _flush_guard in range(100):
  279. if self.session._is_clean():
  280. break
  281. self.session.flush()
  282. else:
  283. raise exc.FlushError(
  284. "Over 100 subsequent flushes have occurred within "
  285. "session.commit() - is an after_flush() hook "
  286. "creating new objects?")
  287. if self._parent is None and self.session.twophase:
  288. try:
  289. for t in set(self._connections.values()):
  290. t[1].prepare()
  291. except:
  292. with util.safe_reraise():
  293. self.rollback()
  294. self._state = PREPARED
  295. def commit(self):
  296. self._assert_active(prepared_ok=True)
  297. if self._state is not PREPARED:
  298. self._prepare_impl()
  299. if self._parent is None or self.nested:
  300. for t in set(self._connections.values()):
  301. t[1].commit()
  302. self._state = COMMITTED
  303. self.session.dispatch.after_commit(self.session)
  304. if self.session._enable_transaction_accounting:
  305. self._remove_snapshot()
  306. self.close()
  307. return self._parent
  308. def rollback(self, _capture_exception=False):
  309. self._assert_active(prepared_ok=True, rollback_ok=True)
  310. stx = self.session.transaction
  311. if stx is not self:
  312. for subtransaction in stx._iterate_parents(upto=self):
  313. subtransaction.close()
  314. if self._state in (ACTIVE, PREPARED):
  315. for transaction in self._iterate_parents():
  316. if transaction._parent is None or transaction.nested:
  317. transaction._rollback_impl()
  318. transaction._state = DEACTIVE
  319. break
  320. else:
  321. transaction._state = DEACTIVE
  322. sess = self.session
  323. if self.session._enable_transaction_accounting and \
  324. not sess._is_clean():
  325. # if items were added, deleted, or mutated
  326. # here, we need to re-restore the snapshot
  327. util.warn(
  328. "Session's state has been changed on "
  329. "a non-active transaction - this state "
  330. "will be discarded.")
  331. self._restore_snapshot(dirty_only=self.nested)
  332. self.close()
  333. if self._parent and _capture_exception:
  334. self._parent._rollback_exception = sys.exc_info()[1]
  335. sess.dispatch.after_soft_rollback(sess, self)
  336. return self._parent
  337. def _rollback_impl(self):
  338. for t in set(self._connections.values()):
  339. t[1].rollback()
  340. if self.session._enable_transaction_accounting:
  341. self._restore_snapshot(dirty_only=self.nested)
  342. self.session.dispatch.after_rollback(self.session)
  343. def close(self):
  344. self.session.transaction = self._parent
  345. if self._parent is None:
  346. for connection, transaction, autoclose in \
  347. set(self._connections.values()):
  348. if autoclose:
  349. connection.close()
  350. else:
  351. transaction.close()
  352. self._state = CLOSED
  353. if self.session.dispatch.after_transaction_end:
  354. self.session.dispatch.after_transaction_end(self.session, self)
  355. if self._parent is None:
  356. if not self.session.autocommit:
  357. self.session.begin()
  358. self.session = None
  359. self._connections = None
  360. def __enter__(self):
  361. return self
  362. def __exit__(self, type, value, traceback):
  363. self._assert_active(deactive_ok=True, prepared_ok=True)
  364. if self.session.transaction is None:
  365. return
  366. if type is None:
  367. try:
  368. self.commit()
  369. except:
  370. with util.safe_reraise():
  371. self.rollback()
  372. else:
  373. self.rollback()
  374. class Session(_SessionClassMethods):
  375. """Manages persistence operations for ORM-mapped objects.
  376. The Session's usage paradigm is described at :doc:`/orm/session`.
  377. """
  378. public_methods = (
  379. '__contains__', '__iter__', 'add', 'add_all', 'begin', 'begin_nested',
  380. 'close', 'commit', 'connection', 'delete', 'execute', 'expire',
  381. 'expire_all', 'expunge', 'expunge_all', 'flush', 'get_bind',
  382. 'is_modified',
  383. 'merge', 'query', 'refresh', 'rollback',
  384. 'scalar')
  385. def __init__(self, bind=None, autoflush=True, expire_on_commit=True,
  386. _enable_transaction_accounting=True,
  387. autocommit=False, twophase=False,
  388. weak_identity_map=True, binds=None, extension=None,
  389. info=None,
  390. query_cls=query.Query):
  391. """Construct a new Session.
  392. See also the :class:`.sessionmaker` function which is used to
  393. generate a :class:`.Session`-producing callable with a given
  394. set of arguments.
  395. :param autocommit:
  396. .. warning::
  397. The autocommit flag is **not for general use**, and if it is used,
  398. queries should only be invoked within the span of a
  399. :meth:`.Session.begin` / :meth:`.Session.commit` pair. Executing
  400. queries outside of a demarcated transaction is a legacy mode
  401. of usage, and can in some cases lead to concurrent connection
  402. checkouts.
  403. Defaults to ``False``. When ``True``, the
  404. :class:`.Session` does not keep a persistent transaction running, and
  405. will acquire connections from the engine on an as-needed basis,
  406. returning them immediately after their use. Flushes will begin and
  407. commit (or possibly rollback) their own transaction if no
  408. transaction is present. When using this mode, the
  409. :meth:`.Session.begin` method is used to explicitly start
  410. transactions.
  411. .. seealso::
  412. :ref:`session_autocommit`
  413. :param autoflush: When ``True``, all query operations will issue a
  414. :meth:`~.Session.flush` call to this ``Session`` before proceeding.
  415. This is a convenience feature so that :meth:`~.Session.flush` need
  416. not be called repeatedly in order for database queries to retrieve
  417. results. It's typical that ``autoflush`` is used in conjunction with
  418. ``autocommit=False``. In this scenario, explicit calls to
  419. :meth:`~.Session.flush` are rarely needed; you usually only need to
  420. call :meth:`~.Session.commit` (which flushes) to finalize changes.
  421. :param bind: An optional :class:`.Engine` or :class:`.Connection` to
  422. which this ``Session`` should be bound. When specified, all SQL
  423. operations performed by this session will execute via this
  424. connectable.
  425. :param binds: An optional dictionary which contains more granular
  426. "bind" information than the ``bind`` parameter provides. This
  427. dictionary can map individual :class`.Table`
  428. instances as well as :class:`~.Mapper` instances to individual
  429. :class:`.Engine` or :class:`.Connection` objects. Operations which
  430. proceed relative to a particular :class:`.Mapper` will consult this
  431. dictionary for the direct :class:`.Mapper` instance as
  432. well as the mapper's ``mapped_table`` attribute in order to locate a
  433. connectable to use. The full resolution is described in the
  434. :meth:`.Session.get_bind`.
  435. Usage looks like::
  436. Session = sessionmaker(binds={
  437. SomeMappedClass: create_engine('postgresql://engine1'),
  438. somemapper: create_engine('postgresql://engine2'),
  439. some_table: create_engine('postgresql://engine3'),
  440. })
  441. Also see the :meth:`.Session.bind_mapper`
  442. and :meth:`.Session.bind_table` methods.
  443. :param \class_: Specify an alternate class other than
  444. ``sqlalchemy.orm.session.Session`` which should be used by the
  445. returned class. This is the only argument that is local to the
  446. :class:`.sessionmaker` function, and is not sent directly to the
  447. constructor for ``Session``.
  448. :param _enable_transaction_accounting: Defaults to ``True``. A
  449. legacy-only flag which when ``False`` disables *all* 0.5-style
  450. object accounting on transaction boundaries, including auto-expiry
  451. of instances on rollback and commit, maintenance of the "new" and
  452. "deleted" lists upon rollback, and autoflush of pending changes upon
  453. :meth:`~.Session.begin`, all of which are interdependent.
  454. :param expire_on_commit: Defaults to ``True``. When ``True``, all
  455. instances will be fully expired after each :meth:`~.commit`,
  456. so that all attribute/object access subsequent to a completed
  457. transaction will load from the most recent database state.
  458. :param extension: An optional
  459. :class:`~.SessionExtension` instance, or a list
  460. of such instances, which will receive pre- and post- commit and
  461. flush events, as well as a post-rollback event. **Deprecated.**
  462. Please see :class:`.SessionEvents`.
  463. :param info: optional dictionary of arbitrary data to be associated
  464. with this :class:`.Session`. Is available via the :attr:`.Session.info`
  465. attribute. Note the dictionary is copied at construction time so
  466. that modifications to the per-:class:`.Session` dictionary will be local
  467. to that :class:`.Session`.
  468. .. versionadded:: 0.9.0
  469. :param query_cls: Class which should be used to create new Query
  470. objects, as returned by the :meth:`~.Session.query` method. Defaults
  471. to :class:`.Query`.
  472. :param twophase: When ``True``, all transactions will be started as
  473. a "two phase" transaction, i.e. using the "two phase" semantics
  474. of the database in use along with an XID. During a
  475. :meth:`~.commit`, after :meth:`~.flush` has been issued for all
  476. attached databases, the :meth:`~.TwoPhaseTransaction.prepare` method
  477. on each database's :class:`.TwoPhaseTransaction` will be called.
  478. This allows each database to roll back the entire transaction,
  479. before each transaction is committed.
  480. :param weak_identity_map: Defaults to ``True`` - when set to
  481. ``False``, objects placed in the :class:`.Session` will be
  482. strongly referenced until explicitly removed or the
  483. :class:`.Session` is closed. **Deprecated** - this option
  484. is obsolete.
  485. """
  486. if weak_identity_map:
  487. self._identity_cls = identity.WeakInstanceDict
  488. else:
  489. util.warn_deprecated("weak_identity_map=False is deprecated. "
  490. "This feature is not needed.")
  491. self._identity_cls = identity.StrongInstanceDict
  492. self.identity_map = self._identity_cls()
  493. self._new = {} # InstanceState->object, strong refs object
  494. self._deleted = {} # same
  495. self.bind = bind
  496. self.__binds = {}
  497. self._flushing = False
  498. self._warn_on_events = False
  499. self.transaction = None
  500. self.hash_key = _new_sessionid()
  501. self.autoflush = autoflush
  502. self.autocommit = autocommit
  503. self.expire_on_commit = expire_on_commit
  504. self._enable_transaction_accounting = _enable_transaction_accounting
  505. self.twophase = twophase
  506. self._query_cls = query_cls
  507. if info:
  508. self.info.update(info)
  509. if extension:
  510. for ext in util.to_list(extension):
  511. SessionExtension._adapt_listener(self, ext)
  512. if binds is not None:
  513. for mapperortable, bind in binds.items():
  514. insp = inspect(mapperortable)
  515. if insp.is_selectable:
  516. self.bind_table(mapperortable, bind)
  517. elif insp.is_mapper:
  518. self.bind_mapper(mapperortable, bind)
  519. else:
  520. assert False
  521. if not self.autocommit:
  522. self.begin()
  523. _sessions[self.hash_key] = self
  524. connection_callable = None
  525. transaction = None
  526. """The current active or inactive :class:`.SessionTransaction`."""
  527. @util.memoized_property
  528. def info(self):
  529. """A user-modifiable dictionary.
  530. The initial value of this dictioanry can be populated using the
  531. ``info`` argument to the :class:`.Session` constructor or
  532. :class:`.sessionmaker` constructor or factory methods. The dictionary
  533. here is always local to this :class:`.Session` and can be modified
  534. independently of all other :class:`.Session` objects.
  535. .. versionadded:: 0.9.0
  536. """
  537. return {}
  538. def begin(self, subtransactions=False, nested=False):
  539. """Begin a transaction on this :class:`.Session`.
  540. If this Session is already within a transaction, either a plain
  541. transaction or nested transaction, an error is raised, unless
  542. ``subtransactions=True`` or ``nested=True`` is specified.
  543. The ``subtransactions=True`` flag indicates that this
  544. :meth:`~.Session.begin` can create a subtransaction if a transaction
  545. is already in progress. For documentation on subtransactions, please
  546. see :ref:`session_subtransactions`.
  547. The ``nested`` flag begins a SAVEPOINT transaction and is equivalent
  548. to calling :meth:`~.Session.begin_nested`. For documentation on
  549. SAVEPOINT transactions, please see :ref:`session_begin_nested`.
  550. """
  551. if self.transaction is not None:
  552. if subtransactions or nested:
  553. self.transaction = self.transaction._begin(
  554. nested=nested)
  555. else:
  556. raise sa_exc.InvalidRequestError(
  557. "A transaction is already begun. Use "
  558. "subtransactions=True to allow subtransactions.")
  559. else:
  560. self.transaction = SessionTransaction(
  561. self, nested=nested)
  562. return self.transaction # needed for __enter__/__exit__ hook
  563. def begin_nested(self):
  564. """Begin a `nested` transaction on this Session.
  565. The target database(s) must support SQL SAVEPOINTs or a
  566. SQLAlchemy-supported vendor implementation of the idea.
  567. For documentation on SAVEPOINT
  568. transactions, please see :ref:`session_begin_nested`.
  569. """
  570. return self.begin(nested=True)
  571. def rollback(self):
  572. """Rollback the current transaction in progress.
  573. If no transaction is in progress, this method is a pass-through.
  574. This method rolls back the current transaction or nested transaction
  575. regardless of subtransactions being in effect. All subtransactions up
  576. to the first real transaction are closed. Subtransactions occur when
  577. :meth:`.begin` is called multiple times.
  578. .. seealso::
  579. :ref:`session_rollback`
  580. """
  581. if self.transaction is None:
  582. pass
  583. else:
  584. self.transaction.rollback()
  585. def commit(self):
  586. """Flush pending changes and commit the current transaction.
  587. If no transaction is in progress, this method raises an
  588. :exc:`~sqlalchemy.exc.InvalidRequestError`.
  589. By default, the :class:`.Session` also expires all database
  590. loaded state on all ORM-managed attributes after transaction commit.
  591. This so that subsequent operations load the most recent
  592. data from the database. This behavior can be disabled using
  593. the ``expire_on_commit=False`` option to :class:`.sessionmaker` or
  594. the :class:`.Session` constructor.
  595. If a subtransaction is in effect (which occurs when begin() is called
  596. multiple times), the subtransaction will be closed, and the next call
  597. to ``commit()`` will operate on the enclosing transaction.
  598. When using the :class:`.Session` in its default mode of
  599. ``autocommit=False``, a new transaction will
  600. be begun immediately after the commit, but note that the newly begun
  601. transaction does *not* use any connection resources until the first
  602. SQL is actually emitted.
  603. .. seealso::
  604. :ref:`session_committing`
  605. """
  606. if self.transaction is None:
  607. if not self.autocommit:
  608. self.begin()
  609. else:
  610. raise sa_exc.InvalidRequestError("No transaction is begun.")
  611. self.transaction.commit()
  612. def prepare(self):
  613. """Prepare the current transaction in progress for two phase commit.
  614. If no transaction is in progress, this method raises an
  615. :exc:`~sqlalchemy.exc.InvalidRequestError`.
  616. Only root transactions of two phase sessions can be prepared. If the
  617. current transaction is not such, an
  618. :exc:`~sqlalchemy.exc.InvalidRequestError` is raised.
  619. """
  620. if self.transaction is None:
  621. if not self.autocommit:
  622. self.begin()
  623. else:
  624. raise sa_exc.InvalidRequestError("No transaction is begun.")
  625. self.transaction.prepare()
  626. def connection(self, mapper=None, clause=None,
  627. bind=None,
  628. close_with_result=False,
  629. **kw):
  630. """Return a :class:`.Connection` object corresponding to this
  631. :class:`.Session` object's transactional state.
  632. If this :class:`.Session` is configured with ``autocommit=False``,
  633. either the :class:`.Connection` corresponding to the current
  634. transaction is returned, or if no transaction is in progress, a new
  635. one is begun and the :class:`.Connection` returned (note that no
  636. transactional state is established with the DBAPI until the first
  637. SQL statement is emitted).
  638. Alternatively, if this :class:`.Session` is configured with
  639. ``autocommit=True``, an ad-hoc :class:`.Connection` is returned
  640. using :meth:`.Engine.contextual_connect` on the underlying
  641. :class:`.Engine`.
  642. Ambiguity in multi-bind or unbound :class:`.Session` objects can be
  643. resolved through any of the optional keyword arguments. This
  644. ultimately makes usage of the :meth:`.get_bind` method for resolution.
  645. :param bind:
  646. Optional :class:`.Engine` to be used as the bind. If
  647. this engine is already involved in an ongoing transaction,
  648. that connection will be used. This argument takes precedence
  649. over ``mapper``, ``clause``.
  650. :param mapper:
  651. Optional :func:`.mapper` mapped class, used to identify
  652. the appropriate bind. This argument takes precedence over
  653. ``clause``.
  654. :param clause:
  655. A :class:`.ClauseElement` (i.e. :func:`~.sql.expression.select`,
  656. :func:`~.sql.expression.text`,
  657. etc.) which will be used to locate a bind, if a bind
  658. cannot otherwise be identified.
  659. :param close_with_result: Passed to :meth:`.Engine.connect`, indicating
  660. the :class:`.Connection` should be considered "single use",
  661. automatically closing when the first result set is closed. This
  662. flag only has an effect if this :class:`.Session` is configured with
  663. ``autocommit=True`` and does not already have a transaction
  664. in progress.
  665. :param \**kw:
  666. Additional keyword arguments are sent to :meth:`get_bind()`,
  667. allowing additional arguments to be passed to custom
  668. implementations of :meth:`get_bind`.
  669. """
  670. if bind is None:
  671. bind = self.get_bind(mapper, clause=clause, **kw)
  672. return self._connection_for_bind(bind,
  673. close_with_result=close_with_result)
  674. def _connection_for_bind(self, engine, **kwargs):
  675. if self.transaction is not None:
  676. return self.transaction._connection_for_bind(engine)
  677. else:
  678. return engine.contextual_connect(**kwargs)
  679. def execute(self, clause, params=None, mapper=None, bind=None, **kw):
  680. """Execute a SQL expression construct or string statement within
  681. the current transaction.
  682. Returns a :class:`.ResultProxy` representing
  683. results of the statement execution, in the same manner as that of an
  684. :class:`.Engine` or
  685. :class:`.Connection`.
  686. E.g.::
  687. result = session.execute(
  688. user_table.select().where(user_table.c.id == 5)
  689. )
  690. :meth:`~.Session.execute` accepts any executable clause construct, such
  691. as :func:`~.sql.expression.select`,
  692. :func:`~.sql.expression.insert`,
  693. :func:`~.sql.expression.update`,
  694. :func:`~.sql.expression.delete`, and
  695. :func:`~.sql.expression.text`. Plain SQL strings can be passed
  696. as well, which in the case of :meth:`.Session.execute` only
  697. will be interpreted the same as if it were passed via a
  698. :func:`~.expression.text` construct. That is, the following usage::
  699. result = session.execute(
  700. "SELECT * FROM user WHERE id=:param",
  701. {"param":5}
  702. )
  703. is equivalent to::
  704. from sqlalchemy import text
  705. result = session.execute(
  706. text("SELECT * FROM user WHERE id=:param"),
  707. {"param":5}
  708. )
  709. The second positional argument to :meth:`.Session.execute` is an
  710. optional parameter set. Similar to that of
  711. :meth:`.Connection.execute`, whether this is passed as a single
  712. dictionary, or a list of dictionaries, determines whether the DBAPI
  713. cursor's ``execute()`` or ``executemany()`` is used to execute the
  714. statement. An INSERT construct may be invoked for a single row::
  715. result = session.execute(users.insert(), {"id": 7, "name": "somename"})
  716. or for multiple rows::
  717. result = session.execute(users.insert(), [
  718. {"id": 7, "name": "somename7"},
  719. {"id": 8, "name": "somename8"},
  720. {"id": 9, "name": "somename9"}
  721. ])
  722. The statement is executed within the current transactional context of
  723. this :class:`.Session`. The :class:`.Connection` which is used
  724. to execute the statement can also be acquired directly by
  725. calling the :meth:`.Session.connection` method. Both methods use
  726. a rule-based resolution scheme in order to determine the
  727. :class:`.Connection`, which in the average case is derived directly
  728. from the "bind" of the :class:`.Session` itself, and in other cases
  729. can be based on the :func:`.mapper`
  730. and :class:`.Table` objects passed to the method; see the documentation
  731. for :meth:`.Session.get_bind` for a full description of this scheme.
  732. The :meth:`.Session.execute` method does *not* invoke autoflush.
  733. The :class:`.ResultProxy` returned by the :meth:`.Session.execute`
  734. method is returned with the "close_with_result" flag set to true;
  735. the significance of this flag is that if this :class:`.Session` is
  736. autocommitting and does not have a transaction-dedicated
  737. :class:`.Connection` available, a temporary :class:`.Connection` is
  738. established for the statement execution, which is closed (meaning,
  739. returned to the connection pool) when the :class:`.ResultProxy` has
  740. consumed all available data. This applies *only* when the
  741. :class:`.Session` is configured with autocommit=True and no
  742. transaction has been started.
  743. :param clause:
  744. An executable statement (i.e. an :class:`.Executable` expression
  745. such as :func:`.expression.select`) or string SQL statement
  746. to be executed.
  747. :param params:
  748. Optional dictionary, or list of dictionaries, containing
  749. bound parameter values. If a single dictionary, single-row
  750. execution occurs; if a list of dictionaries, an
  751. "executemany" will be invoked. The keys in each dictionary
  752. must correspond to parameter names present in the statement.
  753. :param mapper:
  754. Optional :func:`.mapper` or mapped class, used to identify
  755. the appropriate bind. This argument takes precedence over
  756. ``clause`` when locating a bind. See :meth:`.Session.get_bind`
  757. for more details.
  758. :param bind:
  759. Optional :class:`.Engine` to be used as the bind. If
  760. this engine is already involved in an ongoing transaction,
  761. that connection will be used. This argument takes
  762. precedence over ``mapper`` and ``clause`` when locating
  763. a bind.
  764. :param \**kw:
  765. Additional keyword arguments are sent to :meth:`.Session.get_bind()`
  766. to allow extensibility of "bind" schemes.
  767. .. seealso::
  768. :ref:`sqlexpression_toplevel` - Tutorial on using Core SQL
  769. constructs.
  770. :ref:`connections_toplevel` - Further information on direct
  771. statement execution.
  772. :meth:`.Connection.execute` - core level statement execution
  773. method, which is :meth:`.Session.execute` ultimately uses
  774. in order to execute the statement.
  775. """
  776. clause = expression._literal_as_text(clause)
  777. if bind is None:
  778. bind = self.get_bind(mapper, clause=clause, **kw)
  779. return self._connection_for_bind(bind, close_with_result=True).execute(
  780. clause, params or {})
  781. def scalar(self, clause, params=None, mapper=None, bind=None, **kw):
  782. """Like :meth:`~.Session.execute` but return a scalar result."""
  783. return self.execute(
  784. clause, params=params, mapper=mapper, bind=bind, **kw).scalar()
  785. def close(self):
  786. """Close this Session.
  787. This clears all items and ends any transaction in progress.
  788. If this session were created with ``autocommit=False``, a new
  789. transaction is immediately begun. Note that this new transaction does
  790. not use any connection resources until they are first needed.
  791. """
  792. self.expunge_all()
  793. if self.transaction is not None:
  794. for transaction in self.transaction._iterate_parents():
  795. transaction.close()
  796. def expunge_all(self):
  797. """Remove all object instances from this ``Session``.
  798. This is equivalent to calling ``expunge(obj)`` on all objects in this
  799. ``Session``.
  800. """
  801. for state in self.identity_map.all_states() + list(self._new):
  802. state._detach()
  803. self.identity_map = self._identity_cls()
  804. self._new = {}
  805. self._deleted = {}
  806. # TODO: need much more test coverage for bind_mapper() and similar !
  807. # TODO: + crystallize + document resolution order
  808. # vis. bind_mapper/bind_table
  809. def bind_mapper(self, mapper, bind):
  810. """Bind operations for a mapper to a Connectable.
  811. mapper
  812. A mapper instance or mapped class
  813. bind
  814. Any Connectable: a :class:`.Engine` or :class:`.Connection`.
  815. All subsequent operations involving this mapper will use the given
  816. `bind`.
  817. """
  818. if isinstance(mapper, type):
  819. mapper = class_mapper(mapper)
  820. self.__binds[mapper.base_mapper] = bind
  821. for t in mapper._all_tables:
  822. self.__binds[t] = bind
  823. def bind_table(self, table, bind):
  824. """Bind operations on a Table to a Connectable.
  825. table
  826. A :class:`.Table` instance
  827. bind
  828. Any Connectable: a :class:`.Engine` or :class:`.Connection`.
  829. All subsequent operations involving this :class:`.Table` will use the
  830. given `bind`.
  831. """
  832. self.__binds[table] = bind
  833. def get_bind(self, mapper=None, clause=None):
  834. """Return a "bind" to which this :class:`.Session` is bound.
  835. The "bind" is usually an instance of :class:`.Engine`,
  836. except in the case where the :class:`.Session` has been
  837. explicitly bound directly to a :class:`.Connection`.
  838. For a multiply-bound or unbound :class:`.Session`, the
  839. ``mapper`` or ``clause`` arguments are used to determine the
  840. appropriate bind to return.
  841. Note that the "mapper" argument is usually present
  842. when :meth:`.Session.get_bind` is called via an ORM
  843. operation such as a :meth:`.Session.query`, each
  844. individual INSERT/UPDATE/DELETE operation within a
  845. :meth:`.Session.flush`, call, etc.
  846. The order of resolution is:
  847. 1. if mapper given and session.binds is present,
  848. locate a bind based on mapper.
  849. 2. if clause given and session.binds is present,
  850. locate a bind based on :class:`.Table` objects
  851. found in the given clause present in session.binds.
  852. 3. if session.bind is present, return that.
  853. 4. if clause given, attempt to return a bind
  854. linked to the :class:`.MetaData` ultimately
  855. associated with the clause.
  856. 5. if mapper given, attempt to return a bind
  857. linked to the :class:`.MetaData` ultimately
  858. associated with the :class:`.Table` or other
  859. selectable to which the mapper is mapped.
  860. 6. No bind can be found, :exc:`~sqlalchemy.exc.UnboundExecutionError`
  861. is raised.
  862. :param mapper:
  863. Optional :func:`.mapper` mapped class or instance of
  864. :class:`.Mapper`. The bind can be derived from a :class:`.Mapper`
  865. first by consulting the "binds" map associated with this
  866. :class:`.Session`, and secondly by consulting the :class:`.MetaData`
  867. associated with the :class:`.Table` to which the :class:`.Mapper`
  868. is mapped for a bind.
  869. :param clause:
  870. A :class:`.ClauseElement` (i.e. :func:`~.sql.expression.select`,
  871. :func:`~.sql.expression.text`,
  872. etc.). If the ``mapper`` argument is not present or could not
  873. produce a bind, the given expression construct will be searched
  874. for a bound element, typically a :class:`.Table` associated with
  875. bound :class:`.MetaData`.
  876. """
  877. if mapper is clause is None:
  878. if self.bind:
  879. return self.bind
  880. else:
  881. raise sa_exc.UnboundExecutionError(
  882. "This session is not bound to a single Engine or "
  883. "Connection, and no context was provided to locate "
  884. "a binding.")
  885. c_mapper = mapper is not None and _class_to_mapper(mapper) or None
  886. # manually bound?
  887. if self.__binds:
  888. if c_mapper:
  889. if c_mapper.base_mapper in self.__binds:
  890. return self.__binds[c_mapper.base_mapper]
  891. elif c_mapper.mapped_table in self.__binds:
  892. return self.__binds[c_mapper.mapped_table]
  893. if clause is not None:
  894. for t in sql_util.find_tables(clause, include_crud=True):
  895. if t in self.__binds:
  896. return self.__binds[t]
  897. if self.bind:
  898. return self.bind
  899. if isinstance(clause, sql.expression.ClauseElement) and clause.bind:
  900. return clause.bind
  901. if c_mapper and c_mapper.mapped_table.bind:
  902. return c_mapper.mapped_table.bind
  903. context = []
  904. if mapper is not None:
  905. context.append('mapper %s' % c_mapper)
  906. if clause is not None:
  907. context.append('SQL expression')
  908. raise sa_exc.UnboundExecutionError(
  909. "Could not locate a bind configured on %s or this Session" % (
  910. ', '.join(context)))
  911. def query(self, *entities, **kwargs):
  912. """Return a new :class:`.Query` object corresponding to this
  913. :class:`.Session`."""
  914. return self._query_cls(entities, self, **kwargs)
  915. @property
  916. @util.contextmanager
  917. def no_autoflush(self):
  918. """Return a context manager that disables autoflush.
  919. e.g.::
  920. with session.no_autoflush:
  921. some_object = SomeClass()
  922. session.add(some_object)
  923. # won't autoflush
  924. some_object.related_thing = session.query(SomeRelated).first()
  925. Operations that proceed within the ``with:`` block
  926. will not be subject to flushes occurring upon query
  927. access. This is useful when initializing a series
  928. of objects which involve existing database queries,
  929. where the uncompleted object should not yet be flushed.
  930. .. versionadded:: 0.7.6
  931. """
  932. autoflush = self.autoflush
  933. self.autoflush = False
  934. yield self
  935. self.autoflush = autoflush
  936. def _autoflush(self):
  937. if self.autoflush and not self._flushing:
  938. try:
  939. self.flush()
  940. except sa_exc.StatementError as e:
  941. # note we are reraising StatementError as opposed to
  942. # raising FlushError with "chaining" to remain compatible
  943. # with code that catches StatementError, IntegrityError,
  944. # etc.
  945. e.add_detail(
  946. "raised as a result of Query-invoked autoflush; "
  947. "consider using a session.no_autoflush block if this "
  948. "flush is occurring prematurely")
  949. util.raise_from_cause(e)
  950. def refresh(self, instance, attribute_names=None, lockmode=None):
  951. """Expire and refresh the attributes on the given instance.
  952. A query will be issued to the database and all attributes will be
  953. refreshed with their current database value.
  954. Lazy-loaded relational attributes will remain lazily loaded, so that
  955. the instance-wide refresh operation will be followed immediately by
  956. the lazy load of that attribute.
  957. Eagerly-loaded relational attributes will eagerly load within the
  958. single refresh operation.
  959. Note that a highly isolated transaction will return the same values as
  960. were previously read in that same transaction, regardless of changes
  961. in database state outside of that transaction - usage of
  962. :meth:`~Session.refresh` usually only makes sense if non-ORM SQL
  963. statement were emitted in the ongoing transaction, or if autocommit
  964. mode is turned on.
  965. :param attribute_names: optional. An iterable collection of
  966. string attribute names indicating a subset of attributes to
  967. be refreshed.
  968. :param lockmode: Passed to the :class:`~sqlalchemy.orm.query.Query`
  969. as used by :meth:`~sqlalchemy.orm.query.Query.with_lockmode`.
  970. .. seealso::
  971. :ref:`session_expire` - introductory material
  972. :meth:`.Session.expire`
  973. :meth:`.Session.expire_all`
  974. """
  975. try:
  976. state = attributes.instance_state(instance)
  977. except exc.NO_STATE:
  978. raise exc.UnmappedInstanceError(instance)
  979. self._expire_state(state, attribute_names)
  980. if loading.load_on_ident(
  981. self.query(object_mapper(instance)),
  982. state.key, refresh_state=state,
  983. lockmode=lockmode,
  984. only_load_props=attribute_names) is None:
  985. raise sa_exc.InvalidRequestError(
  986. "Could not refresh instance '%s'" %
  987. instance_str(instance))
  988. def expire_all(self):
  989. """Expires all persistent instances within this Session.
  990. When any attributes on a persistent instance is next accessed,
  991. a query will be issued using the
  992. :class:`.Session` object's current transactional context in order to
  993. load all expired attributes for the given instance. Note that
  994. a highly isolated transaction will return the same values as were
  995. previously read in that same transaction, regardless of changes
  996. in database state outside of that transaction.
  997. To expire individual objects and individual attributes
  998. on those objects, use :meth:`Session.expire`.
  999. The :class:`.Session` object's default behavior is to
  1000. expire all state whenever the :meth:`Session.rollback`
  1001. or :meth:`Session.commit` methods are called, so that new
  1002. st