1. 程式人生 > >SALALchemy Session與scoped_session的源碼分析

SALALchemy Session與scoped_session的源碼分析

一次 def mov ans resource with alc set val

我們發現Session與scoped_session都有一些方法:

但是scoped_session的源碼裏面沒有設置這些方法讓我們從源碼裏去窺探下源碼在哪裏設置了這些方法:

Session裏面的方法放在了public_methods裏面:

技術分享圖片

scoped_session的源碼裏面沒有這些方法?:

技術分享圖片

那它怎麽實現這些方法的呢?

我們看到了它的構造方法:

 def __init__(self, session_factory, scopefunc=None):
        """Construct a new :class:`.scoped_session`.

        :param session_factory: a factory to create new :class:`.Session`
         instances. This is usually, but not necessarily, an instance
         of :class:`.sessionmaker`.
        :param scopefunc: optional function which defines
         the current scope.   If not passed, the :class:`.scoped_session`
         object assumes "thread-local" scope, and will use
         a Python ``threading.local()`` in order to maintain the current
         :class:`.Session`.  If passed, the function should return
         a hashable token; this token will be used as the key in a
         dictionary in order to store and retrieve the current
         :class:`.Session`.

        
""" self.session_factory = session_factory if scopefunc: self.registry = ScopedRegistry(session_factory, scopefunc) else: self.registry = ThreadLocalRegistry(session_factory)

第一次進來時,scopefunc是空的。

走else,

 self.registry = ThreadLocalRegistry(session_factory)
就會實例化:
ThreadLocalRegistry。
class ThreadLocalRegistry(ScopedRegistry):
    """A :class:`.ScopedRegistry` that uses a ``threading.local()``
    variable for storage.

    """

    def __init__(self, createfunc):
        self.createfunc = createfunc
        self.registry = threading.local()

裏面有兩個對象 self.createfunc和registry:

registry是唯一標識,

session加上括號就會執行__call__方法:

技術分享圖片

因為self.registry.value第一次進入沒有值:

所以走except 就是執行self.createfunc()往前找傳的值是session_factory那麽session_factory是誰呢?就是我們傳入的session,也就是實例化了我們的session。

就這就會走下面的方法:

def instrument(name):
    def do(self, *args, **kwargs):
        return getattr(self.registry(), name)(*args, **kwargs)
    return do

for meth in Session.public_methods:
    setattr(scoped_session, meth, instrument(meth))

方法二:

我們發現

class scoped_session(object):
    """Provides scoped management of :class:`.Session` objects.

    See :ref:`unitofwork_contextual` for a tutorial.

    """

    session_factory = None
    """The `session_factory` provided to `__init__` is stored in this
    attribute and may be accessed at a later time.  This can be useful when
    a new non-scoped :class:`.Session` or :class:`.Connection` to the
    database is needed."""

    def __init__(self, session_factory, scopefunc=None):
        """Construct a new :class:`.scoped_session`.

        :param session_factory: a factory to create new :class:`.Session`
         instances. This is usually, but not necessarily, an instance
         of :class:`.sessionmaker`.
        :param scopefunc: optional function which defines
         the current scope.   If not passed, the :class:`.scoped_session`
         object assumes "thread-local" scope, and will use
         a Python ``threading.local()`` in order to maintain the current
         :class:`.Session`.  If passed, the function should return
         a hashable token; this token will be used as the key in a
         dictionary in order to store and retrieve the current
         :class:`.Session`.

        """
        self.session_factory = session_factory

        if scopefunc:
            self.registry = ScopedRegistry(session_factory, scopefunc)
        else:
            self.registry = ThreadLocalRegistry(session_factory)

如果我們給

scopefunc傳值就會走if語句,
class ScopedRegistry(object):
    """A Registry that can store one or multiple instances of a single
    class on the basis of a "scope" function.

    The object implements ``__call__`` as the "getter", so by
    calling ``myregistry()`` the contained object is returned
    for the current scope.

    :param createfunc:
      a callable that returns a new object to be placed in the registry

    :param scopefunc:
      a callable that will return a key to store/retrieve an object.
    """

    def __init__(self, createfunc, scopefunc):
        """Construct a new :class:`.ScopedRegistry`.

        :param createfunc:  A creation function that will generate
          a new value for the current scope, if none is present.

        :param scopefunc:  A function that returns a hashable
          token representing the current scope (such as, current
          thread identifier).

        """
        self.createfunc = createfunc
        self.scopefunc = scopefunc
        self.registry = {}

    def __call__(self):
        key = self.scopefunc()
        try:
            return self.registry[key]
        except KeyError:
            return self.registry.setdefault(key, self.createfunc())

我們看到如果對象加括號就會走__call__方法:

第一次沒有值,就會走except,設置並且實例化session。

往下方法和方式一一樣啦。

在執行到最後我們要加上一句:

session.remove()
我們來看下這句話做了什麽?
    def remove(self):
        """Dispose of the current :class:`.Session`, if present.

        This will first call :meth:`.Session.close` method
        on the current :class:`.Session`, which releases any existing
        transactional/connection resources still being held; transactions
        specifically are rolled back.  The :class:`.Session` is then
        discarded.   Upon next usage within the same scope,
        the :class:`.scoped_session` will produce a new
        :class:`.Session` object.

        """

        if self.registry.has():
            self.registry().close()
        self.registry.clear()

我們進入has看下:

    def has(self):
        return hasattr(self.registry, "value")

如果有值就執行close方法。

然後在執行clear方法:

    def clear(self):
        try:
            del self.registry.value
        except AttributeError:
            pass

SALALchemy Session與scoped_session的源碼分析