博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SQLAlchemy中scoped_session实现线程安全
阅读量:5280 次
发布时间:2019-06-14

本文共 2505 字,大约阅读时间需要 8 分钟。

  不多说,先上代码

from sqlalchemy.orm import sessionmakerfrom sqlalchemy import create_enginefrom sqlalchemy.orm import scoped_sessionengine = 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

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

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

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

转载于:https://www.cnblogs.com/xinsiwei18/p/9630828.html

你可能感兴趣的文章
查看ASP.NET : ViewState
查看>>
Android StageFrightMediaScanner源码解析
查看>>
vue项目中开启Eslint碰到的一些问题及其规范
查看>>
循环队列实现
查看>>
CSS层模型
查看>>
springBoot 项目 jar/war打包 并运行
查看>>
HDU 1501 Zipper
查看>>
打包java程序生成exe
查看>>
八叉树
查看>>
poj 1129 搜索
查看>>
Git 远程仓库
查看>>
HttpClient的巨坑
查看>>
关于静态文本框透明度的问题
查看>>
海量数据、高并发的优化方案
查看>>
javascript的发展及个人笔记
查看>>
全选,反全选,反选,获取选中的值,根据子选择控制全选按钮
查看>>
梦断代码读后感01
查看>>
[CF#250 Div.2 D]The Child and Zoo(并查集)
查看>>
博客园博客插入公式
查看>>
hdu 1028 Ignatius and the Princess III(母函数入门+模板)
查看>>