SALALchemy Session与scoped_session的源码分析

Posted 黎明NB

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SALALchemy Session与scoped_session的源码分析相关的知识,希望对你有一定的参考价值。

我们发现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的源码分析的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy 中的 Session、sessionmaker、scoped_session

scope属性的用途是啥?

python-flask-scoped_session创建session的两种方式

spring 组件Scope(request,session)示例

多线程scoped_session中的SQLAlchemy

关于ORM,以及Python中SQLAlchemy的scoped_session