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. filter()函数过滤序列

    ''' Python内建的filter()函数用于过滤序列. 和map()类似,filter()也接收一个函数和一个序列.和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据 ...

  2. 拒绝降权!教你用 Python 确保制作的短视频独一无二

    1. 场景 前段时间有人私信我,说自己辛辛苦苦剪辑的短视频,上传到某平台后,由于播放量太大,收到 降权 的通知,直接导致这个账号废掉了! 其实,各大视频平台都有自己的一套鉴别算法,针对视频的二次创作, ...

  3. css 那些使用小技巧(兼容性)

    1. inline-block 的兼容性问题 display:inline-block; *display:inline; *zoom:1; 2. Microsoft Edge 自动给数字加下划线 在 ...

  4. Python format格式化函数

    参考资料:https://www.runoob.com/python/att-string-format.html 在学习Python的时候碰到了一个很有趣的格式化输入的技巧,下面记录在此. Pyth ...

  5. f(t) = t的傅里叶系数

    计算机网络课程讲到物理层,布置作业的第一题是求f(t)=t (0≤t≤1)的傅里叶系数. 我们知道任何一个周期函数都可以被傅里叶级数逼近.如果是实值函数,则可以用正弦分量,余弦分量,直流分量来近似.公 ...

  6. 3、尚硅谷_SSM高级整合_创建Maven项目.avi

    Maven中dependencyManagement作用说明 在Maven多模块的时候,管理依赖关系是非常重要的,各种依赖包冲突,查询问题起来非常复杂,于是就用到了<dependencyMana ...

  7. 10、一个action中处理多个方法的调用第二种方法method的方式

    在实际的项目中,经常采用现在的第二种方式在struct.xml中采用清单文件的方式 我们首先来看action package com.bjpowernode.struts2; import com.o ...

  8. cookie和session及token

    cookie,session傻傻分不清楚? 做了这么多年测试,还是分不清什么是cookie,什么是session?很正常,很多初级开发工程师可能到现在都搞不清什么是session,cookie相对来说 ...

  9. Jmeter系列(34)- 详解 Counter 计数器

    如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html 简单介绍 计数器的作用:循环递增生成数 ...

  10. ⚡ vue3 全家桶体验

    前置 从创建一个简单浏览器导航首页项目展开,该篇随笔包含以下内容的简单上手: vite vue3 vuex4 vue-router next 预览效果有助于理清这些内容,限于篇幅,不容易展开叙述.由于 ...