flask 源码专题(五):SqlAlchemy 中操作数据库时session和scoped_session的区别
1原生session:
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy应用.models import Users engine = create_engine(
"mysql+pymysql://root:root@127.0.0.1:3306/pro6?charset=utf8",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
) #from sqlalchemy.orm.session import Session SessionF = sessionmaker(bind=engine)
session = SessionF() print(session) obj1 = Users(name='ctz', email='49274573@qq.com', extra='aaaa') session.add(obj1) session.commit()
session.close()
问题:由于无法提供线程共享功能,所以在开发时要注意,要给每个线程都创建自己的session
打印sesion可知他是sqlalchemy.orm.session.Session的对象
查看Session的源码 可得到:
class Session(_SessionClassMethods):
"""Manages persistence operations for ORM-mapped objects. The Session's usage paradigm is described at :doc:`/orm/session`. """ 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')
2.scoped_session
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy应用.models import Users
from sqlalchemy.orm import scoped_session engine=create_engine(
"mysql+pymysql://root:root@127.0.0.1:3306/pro6?charset=utf8",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
) SessionF=sessionmaker(bind=engine) #scoped_session封装了两个值 Session 和 registry,registry加括号就执行了ThreadLocalRegistry的__call__方法,如果 # 当前本地线程中有session就返回session,没有就将session添加到了本地线程 #self.registry()=session
session=scoped_session(SessionF) print(session)
obj1=Users(name='ctz',email='49274573@qq.com',extra='aaaa') session.remove()
session.query_property()
优点:支持线程安全,为每个线程都创建一个session:
两种方式:通过本地线程Threading.Local()和创建唯一标识的方法(flask 源码专题(三):请求上下文和应用上下文入栈与出栈)
3.源码分析:
首先我们在scoped_session中放入了Sesion对象
SessionF=sessionmaker(bind=engine)
session=scoped_session(Session)
一、scoped_session类中
class scoped_session(object):
session_factory = None
def __init__(self, session_factory, scopefunc=None): #传递过来的那个Session对象
self.session_factory = session_factory
#scopefunc唯一标示函数
if scopefunc:
self.registry = ScopedRegistry(session_factory, scopefunc)
else:
self.registry = ThreadLocalRegistry(session_factory)
第一次进来scopefunc唯一标识为None,我们将Session作为参数传递到ThreadLocalRegistry中,
ThreadLocalRegistry类中
class ThreadLocalRegistry(ScopedRegistry):
"""A :class:`.ScopedRegistry` that uses a ``threading.local()``
variable for storage. """ def __init__(self, createfunc):
#传递过来的那个Session对象
self.createfunc = createfunc
self.registry = threading.local()
#scoped_session.registry()后执行
def __call__(self):
try:
#如果本地线程中有值的话直接将值返回,
return self.registry.value
except AttributeError:
#没有值的话就示例话Session(),并将他存到本地线程中,并把实例的对象返回
#相当于Session()后的对象加到了本地线程中
val = self.registry.value = self.createfunc()
return val
其中__call__()只有当scoped_session.registry加括号执行
那我们怎么调用那些方法呢?
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))
其中 Session就是sqlalchemy.orm.session.Session
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')
在instrument函数中 self.registry()帮我们执行了ThreadLocalRegistry中的___call__方法,拿到了sesion对象
方法源码示例:
def has(self):
return hasattr(self.registry, "value")
def remove(self):
if self.registry.has():
self.registry().close()
self.registry.clear()
实际两种方式原理都是一样的都是第一种,只是第二种将session放到了本地线程中,为每一个进程都设置了一个session,实现了线程安全
flask 源码专题(五):SqlAlchemy 中操作数据库时session和scoped_session的区别的更多相关文章
- SqlAlchemy 中操作数据库时session和scoped_session的区别(源码分析)
原生session: from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine from sqlalch ...
- flask 源码专题(二):请求上下文与全文上下文
源码解析 0. 请求入口 if __name__ == '__main__': app.run() def run(self, host=None, port=None, debug=None, lo ...
- flask 源码专题(九):flask扩展点
1. 信号(源码) 信号,是在flask框架中为我们预留的钩子,让我们可以进行一些自定义操作. pip3 install blinker 2. 根据flask项目的请求流程来进行设置扩展点 中间件 # ...
- flask 源码专题(十一):LocalStack和Local对象实现栈的管理
目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于localstack的实现 3. 总结 04 LocalS ...
- flask 源码专题(六):session处理机制
前言 flask_session是flask框架实现session功能的一个插件,用来替代flask自带的session实现机制,flask默认的session信息保存在cookie中,不够安全和灵活 ...
- mybatis源码专题(1)--------复习jdbc操作,编译mybatis源码,准备为你的简历加分吧
本文是作者原创,版权归作者所有.若要转载,请注明出处.文章中若有错误和疏漏之处,还请各位大佬不吝指出,谢谢大家. 1.mybatis的底层是jdbc操作,我们来回顾一下,如下 运行以后的结果如下图: ...
- flask 源码专题(八):路由加载
1.示例代码 from flask import Flask app = Flask(__name__,static_url_path='/xx') @app.route('/index') def ...
- flask 源码专题(一):app.run()的背后
当我们用Flask写好一个app后, 运行app.run()表示监听指定的端口, 对收到的request运行app生成response并返回. 现在分析一下, 运行app.run()后具体发生了什么事 ...
- flask 源码专题(十):flash源码研究
flash源码 def flash(message, category="message"): flashes = session.get("_flashes" ...
随机推荐
- foreach 集合又抛经典异常了,这次一定要刨根问底
一:背景 1. 讲故事 最近同事在写一段业务逻辑的时候,程序跑起来总是报:集合已修改:可能无法执行枚举操作,硬是没有找到什么情况下会导致这个异常产生,就让我来找一下bug,其实这个异常在座的每个程序员 ...
- animation 动画 与 transition
animation: name duration timing-function delay iteration-count direction; 值 描述 animation-name 规定需要绑定 ...
- win10 VirtualBox无法打开,COM对象创建失败
https://blog.csdn.net/txwtech/article/details/101900464 VirtualBox无法打开,打开后提示创建COM对象失败: 被召者 RC: E_NOI ...
- VNC连接cnetos图形化界面
VNC连接cnetos图形化界面 Linux系统在服务器上一般都直接最小化安装,是不安装图形界面的,但是有时候,有一些特殊情况,需要使用图形界面,而下面就利用VNC来实现类似windows的远程桌面功 ...
- Redis->主从复制->哨兵模式(高可用)
一:安装redis $ yum -y install gcc $ yum -y install gcc-c++ $ wget http://download.redis.io/releases/red ...
- #linux vscode 保存总提示“Retry as sudo”
linux中,对不同路径下的文件,系统默认指定了不同的操作权限(读/写/执行),出现这个问题是由于文件的权限不足造成的.(路径为/opt/lampp/htdocs/LearnPHP_jayce/hel ...
- 使用itext asian 解决中文不显示的问题
本人使用的itextpdf版本是5.4.3<dependency> <groupId>com.itextpdf</groupId> <artifactId&g ...
- 详述@Responsebody和HTTP异步请求的关系
Map.ModelAndView.User.List等对象都可以作为返回值.上述这两种对象都可以使用此注解.使用此注解即表示是在同一次请求的响应体里返回.浏览器以异步http的方式来接收.比如后端的M ...
- React实战教程之从零开始手把手教你使用 React 最新特性Hooks API 打造一款计算机知识测验App
项目演示地址 项目演示地址 项目代码结构 前言 React 框架的优雅不言而喻,组件化的编程思想使得React框架开发的项目代码简洁,易懂,但早期 React 类组件的写法略显繁琐.React Hoo ...
- C++ Primer Plus(四)
完整阅读C++ Primer Plus 系统重新学习C++语言部分,记录重要但易被忽略的,关键但易被遗忘的. 友元.异常和其他 1.抛出异常类时,虽然catch的是一个引用,但是也会产生一次拷贝,因为 ...