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
so,self.registry()得到的就是数据库操作句柄,所以do函数里最终还是获取到Session里的方法,并执行
当然第一次add操作,会实例化,第二次就直接去local中取,就不走异常分支了
所以这种方式在线程上是更安全的
SQLAlchemy中scoped_session实现线程安全的更多相关文章
- SQLAlchemy 中的 Session、sessionmaker、scoped_session
目录 一.关于 Session 1. Session是缓存吗? 2. Session作用: 3. Session生命周期: 4. Session什么时候创建,提交,关闭? 4. 获取一个Session ...
- flask SQLAlchemy中一对多的关系实现
SQLAlchemy是Python中比较优秀的orm框架,在SQLAlchemy中定义了多种数据库表的对应关系, 其中一对多是一种比较常见的关系.利用flask sqlalchemy实现一对多的关系如 ...
- 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法
[源码下载] 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法 作者:webabcd 介绍重新想象 Wi ...
- Java中的守护线程和非守护线程(转载)
<什么是守护线程,什么是非守护线程> Java有两种Thread:"守护线程Daemon"(守护线程)与"用户线程User"(非守护线程). 用户线 ...
- springmvc中request的线程安全问题
SpringMvc学习心得(四)springmvc中request的线程安全问题 标签: springspring mvc框架线程安全 2016-03-19 11:25 611人阅读 评论(1) 收藏 ...
- Unity 中 使用c#线程
使用条件 天下没有免费的午餐,在我使用unity的那一刻,我就感觉到不自在,因为开源所以不知道底层实现,如果只是简单的做点简单游戏,那就无所谓的了,但真正用到实际地方的时候,就会发现一个挨着一个坑 ...
- Java中的守护线程 & 非守护线程(简介)
Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...
- HttpApplication中的异步线程
一.Asp.net中的线程池设置 在Asp.net的服务处理中,每当服务器收到一个请求,HttpRuntime将从HttpApplication池中获取一个HttpApplication对象处理此请求 ...
- c#中如何跨线程调用windows窗体控件
c#中如何跨线程调用windows窗体控件? 我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍.首 ...
随机推荐
- html学习笔记五
关于服务端和client的校验问题 上述的表格信息填写后发现,即使有些信息不添,依旧能够提交 所以针对此问题,我们要在client进行数据填写信息的增强型校验(必添单元,必须填写有效信息,否则无法提交 ...
- 【Java面试题】15 String s="Hello"; s=s+“world!”;这两行代码执行后,原始的String对象中的内容到底变了没有?String与StringBuffer的超详细讲解!!!!!
1.Java中哪些类是不能被继承的? 不能被继承的是那些用final关键字修饰的类.一般比较基本的类型或防止扩展类无意间破坏原来方法的实现的类型都应该是final的,在java中,System,Str ...
- 【Java面试题】9 abstract class和interface有什么区别?
含有abstract修饰符的class即为抽象类,abstract 类不能创建的实例对象.含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必 ...
- iOS: [UITableView reloadData]
在 iTouch4 或者相差不多的 iPhone 上,不建议在 UIViewController 的 viewWillAppear 的方法中放置 UITableView 的 reloadData 方法 ...
- c++ define的用法(转)
#define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用 ...
- 详解MathType中如何插入特殊符号
在论文写作中,经常会用到一些特殊符号,MathType公式编辑器支持插入特殊符号,并且数量繁多,可以满足用户的需求.本教程将详解MathType如何插入特殊符号. MathType中插入特殊符号的操作 ...
- 什么是mysql的元数据呢?
需求描述: 什么是mysql的元数据?metadata? 概念解释: 简单来说:任何描述数据库的数据就是数据库的元数据库(与数据库中存在的内容相对) 比如,用于描述一个冰箱是如何构成,怎么使用的就是冰 ...
- weblogic11g重置控制密码
Reset the AdminServer Password in WebLogic 11g and 12c If you forget the AdminServer password for yo ...
- 使用HTML5 的跨域通信机制进行数据同步
离线应用系统的设计目标就是在网络离线情况下依然可以操作我们的应用系统,并在网络畅通的情况下与服务器进行数据交互. 所以离线应用系统最终会做成类似C/S架构的客户端应用程序.这边基于Chrome或者 S ...
- HTTP/2笔记之错误处理和安全
零.前言 这里整理了一下错误和安全相关部分简单记录. 一.HTTP/2错误 1. 错误定义 HTTP/2定义了两种类型错误: 导致整个连接不可使用的错误为连接错误(connection error) ...