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的区别的更多相关文章

  1. SqlAlchemy 中操作数据库时session和scoped_session的区别(源码分析)

    原生session: from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine from sqlalch ...

  2. flask 源码专题(二):请求上下文与全文上下文

    源码解析 0. 请求入口 if __name__ == '__main__': app.run() def run(self, host=None, port=None, debug=None, lo ...

  3. flask 源码专题(九):flask扩展点

    1. 信号(源码) 信号,是在flask框架中为我们预留的钩子,让我们可以进行一些自定义操作. pip3 install blinker 2. 根据flask项目的请求流程来进行设置扩展点 中间件 # ...

  4. flask 源码专题(十一):LocalStack和Local对象实现栈的管理

    目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于localstack的实现 3. 总结 04 LocalS ...

  5. flask 源码专题(六):session处理机制

    前言 flask_session是flask框架实现session功能的一个插件,用来替代flask自带的session实现机制,flask默认的session信息保存在cookie中,不够安全和灵活 ...

  6. mybatis源码专题(1)--------复习jdbc操作,编译mybatis源码,准备为你的简历加分吧

    本文是作者原创,版权归作者所有.若要转载,请注明出处.文章中若有错误和疏漏之处,还请各位大佬不吝指出,谢谢大家. 1.mybatis的底层是jdbc操作,我们来回顾一下,如下  运行以后的结果如下图: ...

  7. flask 源码专题(八):路由加载

    1.示例代码 from flask import Flask app = Flask(__name__,static_url_path='/xx') @app.route('/index') def ...

  8. flask 源码专题(一):app.run()的背后

    当我们用Flask写好一个app后, 运行app.run()表示监听指定的端口, 对收到的request运行app生成response并返回. 现在分析一下, 运行app.run()后具体发生了什么事 ...

  9. flask 源码专题(十):flash源码研究

    flash源码 def flash(message, category="message"): flashes = session.get("_flashes" ...

随机推荐

  1. 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU启动那些事(11.0)- FlexSPI NOR启动时间(RT1170)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MX RT1170 FlexSPI NOR启动时间. 痞子衡刚刚拿到i.MXRT1170 B0版本的芯片,迫不及待地在上面跑了 ...

  2. cb10a_c++_顺序容器的操作3关系运算符

    cb10a_c++_cb09a_c++_顺序容器的操作3 2 顺序容器的操作3 3 关系运算符 4 所有的容器类型都可以使用 5 比较的容器必须具有相同的容器类型,double不能与int作比较 6 ...

  3. MOJITO 发布一周,爬一波弹幕分析下

    MOJITO 最近一直啥都没写,追个热点都赶不上热乎的,鄙视自己一下. 周董的新歌 「MOJITO」 发售(6 月 12 日的零点)至今大致过去了一周,翻开 B 站 MV 一看,播放量妥妥破千万,弹幕 ...

  4. 手把手教你学Numpy,搞定数据处理——收官篇

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Numpy专题第6篇文章,我们一起来看看Numpy库当中剩余的部分. 数组的持久化 在我们做机器学习模型的研究或者是学习的时候,在完成 ...

  5. Java工程中各种带有O的对象分类笔记

    在Java工程里面,我们总会碰到各种不同的带有O的对象, 对于一个小白来说,经常会混淆这些对象的使用场景,所以在这里mark一下,让自己的代码更加规范,但这个也是Java被诟病的地方,不同的业务需要给 ...

  6. JavaWeb网上图书商城完整项目--day02-16.登录功能各层实现

    /*1.第一步将用户提交的参数封装成javabean对象 * *2.对提交的参数的进行合法性的校验 * *3.通过用户名和密码去查找得到user对象 *如果user对象为null,说明用户名和密码不正 ...

  7. php - 二维数组转一维数组总结

    二维数组转一维数组总结 例如将如下二位数组转以为以为一维数组 $records = [ [ 'id' => 2135, 'first_name' => 'John', 'last_name ...

  8. Oracle 导入数据库dmp文件

    场景:windows2008 R2系统 ,往新安装的oracle11g数据库导入同事给的dmp文件到指定的新建的用户. 1.创建表空间 在导入dmp文件之前,先打开查看dmp文件的表空间名称(tabl ...

  9. Redis五种数据类型应用场景

    目录 1.1 回顾 2.1 应用场景 2.1.1 String 2.1.2 Hash 2.1.3 List 2.1.4 Zet 2.1.5 zset 3.1 小结 1.1 回顾 Redis的五种数据类 ...

  10. 区间dp 能量项链 洛谷p1063

    题目大意:如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为 (Mars单位),新产生的珠子的头标记为m,尾标记为n. 需要时,Mars人就用吸盘夹住 ...