zoukankan      html  css  js  c++  java
  • SQLAlchemy中scoped_session

    from sqlalchemy.orm import sessionmaker
    from sqlalchemy import create_engine
    from sqlalchemy.orm import scoped_session
     
    engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/s6", max_overflow=0, pool_size=5)
    Session = sessionmaker(bind=engine)
     
    # session = Session()
    session = scoped_session(Session)

    obj1 = Users(name="alex1")
    session.add(obj1)

    # 提交事务
    session.commit()
    # 关闭session
    session.close()

    在上面代码中,从连接池中拿连接的时候,Session直接实例化,或者scoped_session进行实例化也可以
    调用时,方法名都是一样的,比如session.add(),我们会猜他两是继承关系
    但实际是class scoped_session(object),并没有继承Session,而且在scoped_session里也没有找到add方法和commit方法... 那它怎么实现的?

     在scoped_session类下面,有个for循环,其中public_methods,在这里面有我们想看到的add,commit方法,上面把每个方法都设置到scoped_session类里,还要看下instrument(meth)到底是个啥玩意?

    public_methods = (
        '__contains__', '__iter__', 'add', 'add_all', 'begin', 'begin_nested',
        'close', 'commit', 'connection', 'delete', 'execute', 'expire',
        'expire_all', 'expunge', 'expunge_all', 'flush', 'get_bind',
        'is_modified', 'bulk_save_objects', 'bulk_insert_mappings',
        'bulk_update_mappings',
        'merge', 'query', 'refresh', 'rollback',
        'scalar')

    在这个函数最终返回了一个do函数,并把name,也就是函数名传了进入实现闭包

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

    所以当执行session.add时,它会去执行do函数,里面封装的name就是add

    do函数中self.registry是个啥玩意呢?其中self指的是scoped_session对象,所以我们可以去看scoped_session进行实例化是都干了些啥

    #session_factory就是传入的Session = sessionmaker(bind=engine)
    self.session_factory = session_factory
     
    if scopefunc:
        self.registry = ScopedRegistry(session_factory, scopefunc)
    else:#scopefunc此时没值,所以走这里
        self.registry = ThreadLocalRegistry(session_factory)

    我们会看到我们需要的self.registry就在上面代码中,那现在主要ThreadLocalRegistry实例化后返回个啥?

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

    createfunc就是传入的session_factory,也就是Session,所以scoped_session对象的registry,是一个ThreadLocalRegistry对象,封装了Session和local对象

    所以self.registry()会执行ThreadLocalRegistry里的__call__方法

    def __call__(self):
        try:
            return self.registry.value  #刚开始value没值,会报错
        except AttributeError:
            val = self.registry.value = self.createfunc()  #走这里Session(),也就是数据库连接操作句柄,并把句柄放入local中
            return val

    self.registry()得到的就是数据库操作句柄,所以do函数里最终还是获取到Session里的方法,并执行

    当然第一次add操作,会实例化,第二次就直接去local中取,就不走异常分支了

    所以这种方式在线程上是更安全的

  • 相关阅读:
    把图片转换成二进制--把二进制转换成图片
    .NET 读取视频文件
    winform ListView创建columnHeader的方法
    VUE篇 3、this指向问题、双向数据绑定 、局部/全局组件、父子传值 、兄弟传值(平行组件传值)
    爬虫 5 scrapy框架 虎牙scrapy示例
    爬虫 空气质量爬取分析
    爬虫 4 selenium
    爬虫3 request3高级 代理操作、模拟登录、单线程+多任务异步协程
    爬虫2 数据解析 --图片 、bs4 、xpath 、l乱码的一个解决方法 “|”
    vue篇 2、简单的轮播图 ajax、简单的音乐播放器、计算属性computed
  • 原文地址:https://www.cnblogs.com/ice5/p/13633599.html
Copyright © 2011-2022 走看看